@tacdaed/fragments 1.0.0-beta.3 → 1.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/README.md +14 -0
  2. package/ng-package.json +20 -0
  3. package/package.json +22 -29
  4. package/src/lib/components/accordion/accordion.component.html +103 -0
  5. package/src/lib/components/accordion/accordion.component.scss +382 -0
  6. package/src/lib/components/accordion/accordion.component.spec.ts +147 -0
  7. package/src/lib/components/accordion/accordion.component.ts +211 -0
  8. package/src/lib/components/accordion/accordion.type.ts +82 -0
  9. package/src/lib/components/breadcrumb/breadcrumb.component.html +43 -0
  10. package/src/lib/components/breadcrumb/breadcrumb.component.scss +112 -0
  11. package/src/lib/components/breadcrumb/breadcrumb.component.spec.ts +33 -0
  12. package/src/lib/components/breadcrumb/breadcrumb.component.ts +103 -0
  13. package/src/lib/components/breadcrumb/breadcrumb.interface.ts +7 -0
  14. package/src/lib/components/button/button.component.html +57 -0
  15. package/src/lib/components/button/button.component.scss +445 -0
  16. package/src/lib/components/button/button.component.spec.ts +99 -0
  17. package/src/lib/components/button/button.component.ts +143 -0
  18. package/src/lib/components/button/button.type.ts +7 -0
  19. package/src/lib/components/card/card.component.html +44 -0
  20. package/src/lib/components/card/card.component.scss +114 -0
  21. package/src/lib/components/card/card.component.spec.ts +65 -0
  22. package/src/lib/components/card/card.component.ts +21 -0
  23. package/src/lib/components/card/card.type.ts +3 -0
  24. package/src/lib/components/code-block/code-block.component.html +55 -0
  25. package/src/lib/components/code-block/code-block.component.scss +122 -0
  26. package/src/lib/components/code-block/code-block.component.spec.ts +81 -0
  27. package/src/lib/components/code-block/code-block.component.ts +302 -0
  28. package/src/lib/components/code-block/code-block.interface.ts +28 -0
  29. package/src/lib/components/code-block/code-block.type.ts +73 -0
  30. package/src/lib/components/decorative/sparkle-field/sparkle-field.component.html +14 -0
  31. package/src/lib/components/decorative/sparkle-field/sparkle-field.component.scss +20 -0
  32. package/src/lib/components/decorative/sparkle-field/sparkle-field.component.spec.ts +38 -0
  33. package/src/lib/components/decorative/sparkle-field/sparkle-field.component.ts +181 -0
  34. package/src/lib/components/input/input-base.ts +187 -0
  35. package/src/lib/components/input/input-calendar/input-calendar.component.html +76 -0
  36. package/src/lib/components/input/input-calendar/input-calendar.component.scss +179 -0
  37. package/src/lib/components/input/input-calendar/input-calendar.component.spec.ts +44 -0
  38. package/src/lib/components/input/input-calendar/input-calendar.component.ts +299 -0
  39. package/src/lib/components/input/input-checkbox/input-checkbox.component.html +37 -0
  40. package/src/lib/components/input/input-checkbox/input-checkbox.component.scss +128 -0
  41. package/src/lib/components/input/input-checkbox/input-checkbox.component.spec.ts +43 -0
  42. package/src/lib/components/input/input-checkbox/input-checkbox.component.ts +112 -0
  43. package/src/lib/components/input/input-checkbox-group/input-checkbox-group.component.html +43 -0
  44. package/src/lib/components/input/input-checkbox-group/input-checkbox-group.component.scss +140 -0
  45. package/src/lib/components/input/input-checkbox-group/input-checkbox-group.component.spec.ts +62 -0
  46. package/src/lib/components/input/input-checkbox-group/input-checkbox-group.component.ts +136 -0
  47. package/src/lib/components/input/input-clock-picker/input-clock-picker.component.html +81 -0
  48. package/src/lib/components/input/input-clock-picker/input-clock-picker.component.scss +228 -0
  49. package/src/lib/components/input/input-clock-picker/input-clock-picker.component.spec.ts +62 -0
  50. package/src/lib/components/input/input-clock-picker/input-clock-picker.component.ts +178 -0
  51. package/src/lib/components/input/input-consts.ts +132 -0
  52. package/src/lib/components/input/input-date/input-date-validators.ts +41 -0
  53. package/src/lib/components/input/input-date/input-date.component.html +41 -0
  54. package/src/lib/components/input/input-date/input-date.component.scss +95 -0
  55. package/src/lib/components/input/input-date/input-date.component.spec.ts +43 -0
  56. package/src/lib/components/input/input-date/input-date.component.ts +359 -0
  57. package/src/lib/components/input/input-date-time/input-date-time.component.html +70 -0
  58. package/src/lib/components/input/input-date-time/input-date-time.component.scss +133 -0
  59. package/src/lib/components/input/input-date-time/input-date-time.component.spec.ts +36 -0
  60. package/src/lib/components/input/input-date-time/input-date-time.component.ts +387 -0
  61. package/src/lib/components/input/input-file-upload/input-file-upload.component.html +89 -0
  62. package/src/lib/components/input/input-file-upload/input-file-upload.component.scss +171 -0
  63. package/src/lib/components/input/input-file-upload/input-file-upload.component.spec.ts +43 -0
  64. package/src/lib/components/input/input-file-upload/input-file-upload.component.ts +351 -0
  65. package/src/lib/components/input/input-interface.ts +8 -0
  66. package/src/lib/components/input/input-number/input-number-validators.ts +0 -0
  67. package/src/lib/components/input/input-number/input-number.component.html +51 -0
  68. package/src/lib/components/input/input-number/input-number.component.scss +140 -0
  69. package/src/lib/components/input/input-number/input-number.component.spec.ts +44 -0
  70. package/src/lib/components/input/input-number/input-number.component.ts +343 -0
  71. package/src/lib/components/input/input-radio-group/input-radio-group.component.html +44 -0
  72. package/src/lib/components/input/input-radio-group/input-radio-group.component.scss +139 -0
  73. package/src/lib/components/input/input-radio-group/input-radio-group.component.spec.ts +58 -0
  74. package/src/lib/components/input/input-radio-group/input-radio-group.component.ts +132 -0
  75. package/src/lib/components/input/input-slider/input-slider.component.html +111 -0
  76. package/src/lib/components/input/input-slider/input-slider.component.scss +203 -0
  77. package/src/lib/components/input/input-slider/input-slider.component.spec.ts +46 -0
  78. package/src/lib/components/input/input-slider/input-slider.component.ts +410 -0
  79. package/src/lib/components/input/input-text/input-text-validators.ts +67 -0
  80. package/src/lib/components/input/input-text/input-text.component.html +71 -0
  81. package/src/lib/components/input/input-text/input-text.component.scss +118 -0
  82. package/src/lib/components/input/input-text/input-text.component.spec.ts +55 -0
  83. package/src/lib/components/input/input-text/input-text.component.ts +215 -0
  84. package/src/lib/components/input/input-time/input-time-validators.ts +42 -0
  85. package/src/lib/components/input/input-time/input-time.component.html +92 -0
  86. package/src/lib/components/input/input-time/input-time.component.scss +191 -0
  87. package/src/lib/components/input/input-time/input-time.component.spec.ts +39 -0
  88. package/src/lib/components/input/input-time/input-time.component.ts +691 -0
  89. package/src/lib/components/input/input-toggle-switch/input-toggle-switch.component.html +36 -0
  90. package/src/lib/components/input/input-toggle-switch/input-toggle-switch.component.scss +121 -0
  91. package/src/lib/components/input/input-toggle-switch/input-toggle-switch.component.spec.ts +54 -0
  92. package/src/lib/components/input/input-toggle-switch/input-toggle-switch.component.ts +117 -0
  93. package/src/lib/components/input/input-type.ts +18 -0
  94. package/src/lib/components/input/input-validation/input-validation.component.html +19 -0
  95. package/src/lib/components/input/input-validation/input-validation.component.scss +39 -0
  96. package/src/lib/components/input/input-validation/input-validation.component.spec.ts +45 -0
  97. package/src/lib/components/input/input-validation/input-validation.component.ts +13 -0
  98. package/src/lib/components/input/input.pipe.ts +14 -0
  99. package/src/lib/components/layout/container/container.component.html +1 -0
  100. package/src/lib/components/layout/container/container.component.scss +33 -0
  101. package/src/lib/components/layout/container/container.component.ts +32 -0
  102. package/src/lib/components/layout/container/container.type.ts +1 -0
  103. package/src/lib/components/layout/divider/divider.component.html +1 -0
  104. package/src/lib/components/layout/divider/divider.component.scss +60 -0
  105. package/src/lib/components/layout/divider/divider.component.ts +38 -0
  106. package/src/lib/components/layout/divider/divider.type.ts +2 -0
  107. package/src/lib/components/layout/section/section.component.html +21 -0
  108. package/src/lib/components/layout/section/section.component.scss +43 -0
  109. package/src/lib/components/layout/section/section.component.ts +33 -0
  110. package/src/lib/components/layout/section/section.type.ts +2 -0
  111. package/src/lib/components/layout/separator/separator.component.html +9 -0
  112. package/src/lib/components/layout/separator/separator.component.scss +52 -0
  113. package/src/lib/components/layout/separator/separator.component.ts +25 -0
  114. package/src/lib/components/layout/separator/separator.type.ts +1 -0
  115. package/src/lib/components/loader/content-blur/content-blur.component.html +13 -0
  116. package/src/lib/components/loader/content-blur/content-blur.component.scss +43 -0
  117. package/src/lib/components/loader/content-blur/content-blur.component.spec.ts +42 -0
  118. package/src/lib/components/loader/content-blur/content-blur.component.ts +34 -0
  119. package/src/lib/components/loader/loader.type.ts +2 -0
  120. package/src/lib/components/loader/progress-bar/progress-bar.component.html +26 -0
  121. package/src/lib/components/loader/progress-bar/progress-bar.component.scss +151 -0
  122. package/src/lib/components/loader/progress-bar/progress-bar.component.spec.ts +47 -0
  123. package/src/lib/components/loader/progress-bar/progress-bar.component.ts +28 -0
  124. package/src/lib/components/loader/progress-bar/progress-bar.type.ts +8 -0
  125. package/src/lib/components/loader/pulse-loader/pulse-loader.component.html +12 -0
  126. package/src/lib/components/loader/pulse-loader/pulse-loader.component.scss +202 -0
  127. package/src/lib/components/loader/pulse-loader/pulse-loader.component.spec.ts +55 -0
  128. package/src/lib/components/loader/pulse-loader/pulse-loader.component.ts +73 -0
  129. package/src/lib/components/loader/pulse-loader/pulse-loader.type.ts +6 -0
  130. package/src/lib/components/loader/skeleton-loader/skeleton-loader.component.html +13 -0
  131. package/src/lib/components/loader/skeleton-loader/skeleton-loader.component.scss +113 -0
  132. package/src/lib/components/loader/skeleton-loader/skeleton-loader.component.spec.ts +37 -0
  133. package/src/lib/components/loader/skeleton-loader/skeleton-loader.component.ts +51 -0
  134. package/src/lib/components/loader/skeleton-loader/skeleton-loader.type.ts +6 -0
  135. package/src/lib/components/loader/spinner/spinner.component.html +20 -0
  136. package/src/lib/components/loader/spinner/spinner.component.scss +137 -0
  137. package/src/lib/components/loader/spinner/spinner.component.spec.ts +43 -0
  138. package/src/lib/components/loader/spinner/spinner.component.ts +32 -0
  139. package/src/lib/components/loader/spinner/spinner.type.ts +6 -0
  140. package/src/lib/components/modal/modal.component.html +47 -0
  141. package/src/lib/components/modal/modal.component.scss +139 -0
  142. package/src/lib/components/modal/modal.component.spec.ts +60 -0
  143. package/src/lib/components/modal/modal.component.ts +83 -0
  144. package/src/lib/components/modal/modal.type.ts +9 -0
  145. package/src/lib/components/morph/blob-moph/blob-moprh.component.spec.ts +79 -0
  146. package/src/lib/components/morph/blob-moph/blob-moprh.component.ts +96 -0
  147. package/src/lib/components/morph/blob-moph/blob-morph.component.html +34 -0
  148. package/src/lib/components/morph/blob-moph/blob-morph.component.scss +7 -0
  149. package/src/lib/components/morph/morph.abstract.ts +13 -0
  150. package/src/lib/components/pagination/pagination.interface.ts +4 -0
  151. package/src/lib/components/pagination/small-pagination/small-pagination.component.html +61 -0
  152. package/src/lib/components/pagination/small-pagination/small-pagination.component.scss +187 -0
  153. package/src/lib/components/pagination/small-pagination/small-pagination.component.spec.ts +88 -0
  154. package/src/lib/components/pagination/small-pagination/small-pagination.component.ts +177 -0
  155. package/src/lib/components/selection-lists/multi-select/multi-select.component.html +170 -0
  156. package/src/lib/components/selection-lists/multi-select/multi-select.component.scss +312 -0
  157. package/src/lib/components/selection-lists/multi-select/multi-select.component.spec.ts +61 -0
  158. package/src/lib/components/selection-lists/multi-select/multi-select.component.ts +372 -0
  159. package/src/lib/components/selection-lists/selection-list/selection-list.component.html +125 -0
  160. package/src/lib/components/selection-lists/selection-list/selection-list.component.scss +267 -0
  161. package/src/lib/components/selection-lists/selection-list/selection-list.component.spec.ts +66 -0
  162. package/src/lib/components/selection-lists/selection-list/selection-list.component.ts +315 -0
  163. package/src/lib/components/selection-lists/selection-lists-base.ts +35 -0
  164. package/src/lib/components/selection-lists/selection-lists-const.ts +17 -0
  165. package/src/lib/components/selection-lists/selection-lists-interface.ts +7 -0
  166. package/src/lib/components/selection-lists/selection-lists.type.ts +1 -0
  167. package/src/lib/components/side-nav/side-nav.component.html +101 -0
  168. package/src/lib/components/side-nav/side-nav.component.scss +295 -0
  169. package/src/lib/components/side-nav/side-nav.component.spec.ts +0 -0
  170. package/src/lib/components/side-nav/side-nav.component.ts +18 -0
  171. package/src/lib/components/side-nav/side-nav.type.ts +28 -0
  172. package/src/lib/components/snackbar/snackbar.component.html +33 -0
  173. package/src/lib/components/snackbar/snackbar.component.scss +195 -0
  174. package/src/lib/components/snackbar/snackbar.component.ts +112 -0
  175. package/src/lib/components/snackbar/snackbar.type.ts +27 -0
  176. package/src/lib/components/status/chip/chip.component.html +51 -0
  177. package/src/lib/components/status/chip/chip.component.scss +149 -0
  178. package/src/lib/components/status/chip/chip.component.spec.ts +62 -0
  179. package/src/lib/components/status/chip/chip.component.ts +83 -0
  180. package/src/lib/components/status/chip/chip.type.ts +42 -0
  181. package/src/lib/components/status/directives/badge/badge.directive.spec.ts +60 -0
  182. package/src/lib/components/status/directives/badge/badge.directive.ts +190 -0
  183. package/src/lib/components/status/directives/badge/badge.interface.ts +19 -0
  184. package/src/lib/components/status/pill/pill.component.html +40 -0
  185. package/src/lib/components/status/pill/pill.component.scss +113 -0
  186. package/src/lib/components/status/pill/pill.component.spec.ts +47 -0
  187. package/src/lib/components/status/pill/pill.component.ts +83 -0
  188. package/src/lib/components/status/pill/pill.type.ts +42 -0
  189. package/src/lib/components/status/status.interface.ts +57 -0
  190. package/src/lib/components/status/status.type.ts +62 -0
  191. package/src/lib/components/status/tag/tag.component.html +39 -0
  192. package/src/lib/components/status/tag/tag.component.scss +140 -0
  193. package/src/lib/components/status/tag/tag.component.spec.ts +47 -0
  194. package/src/lib/components/status/tag/tag.component.ts +83 -0
  195. package/src/lib/components/status/tag/tag.type.ts +42 -0
  196. package/src/lib/components/stepper/stepper.component.html +83 -0
  197. package/src/lib/components/stepper/stepper.component.scss +196 -0
  198. package/src/lib/components/stepper/stepper.component.ts +482 -0
  199. package/src/lib/components/stepper/stepper.type.ts +60 -0
  200. package/src/lib/components/table/table.component.html +438 -0
  201. package/src/lib/components/table/table.component.scss +259 -0
  202. package/src/lib/components/table/table.component.spec.ts +117 -0
  203. package/src/lib/components/table/table.component.ts +215 -0
  204. package/src/lib/components/table/table.enum.ts +4 -0
  205. package/src/lib/components/table/table.function.ts +47 -0
  206. package/src/lib/components/table/table.interface.ts +143 -0
  207. package/src/lib/components/table/table.pipe.ts +62 -0
  208. package/src/lib/components/table/table.type.ts +15 -0
  209. package/src/lib/components/tabs/tabs.component.html +88 -0
  210. package/src/lib/components/tabs/tabs.component.scss +305 -0
  211. package/src/lib/components/tabs/tabs.component.spec.ts +94 -0
  212. package/src/lib/components/tabs/tabs.component.ts +282 -0
  213. package/src/lib/components/tabs/tabs.type.ts +81 -0
  214. package/src/lib/components/title-bar/title-bar.component.html +21 -0
  215. package/src/lib/components/title-bar/title-bar.component.scss +139 -0
  216. package/src/lib/components/title-bar/title-bar.component.spec.ts +44 -0
  217. package/src/lib/components/title-bar/title-bar.component.ts +13 -0
  218. package/src/lib/components/toast/toast.component.html +36 -0
  219. package/src/lib/components/toast/toast.component.scss +241 -0
  220. package/src/lib/components/toast/toast.component.ts +165 -0
  221. package/src/lib/components/toast/toast.type.ts +37 -0
  222. package/src/lib/components/toast-stack/toast-stack.component.html +30 -0
  223. package/src/lib/components/toast-stack/toast-stack.component.scss +35 -0
  224. package/src/lib/components/toast-stack/toast-stack.component.ts +51 -0
  225. package/src/lib/consts/country-prefix.ts +244 -0
  226. package/src/lib/directives/tooltip/popover.directive.ts +274 -0
  227. package/src/lib/directives/tooltip/tooltip.directive.spec.ts +86 -0
  228. package/src/lib/directives/tooltip/tooltip.directive.ts +234 -0
  229. package/src/lib/directives/tooltip/tooltip.interface.ts +29 -0
  230. package/src/lib/directives/tooltip/tooltip.type.ts +9 -0
  231. package/src/lib/interfaces/common.interfaces.ts +4 -0
  232. package/src/lib/pipes/chunk.pipe.ts +16 -0
  233. package/src/lib/pipes/safe-html.pipe.ts +14 -0
  234. package/src/lib/pipes/sanitize-html.pipe.ts +23 -0
  235. package/src/lib/types/base.types.ts +23 -0
  236. package/src/lib/types/common.types.ts +98 -0
  237. package/src/lib/types/form.types.ts +5 -0
  238. package/src/lib/utils/common.utils.ts +53 -0
  239. package/src/lib/utils/date.utils.ts +474 -0
  240. package/src/lib/utils/number.utils.ts +16 -0
  241. package/src/lib/utils/uuid.utils.ts +39 -0
  242. package/src/public-api.ts +114 -0
  243. package/tsconfig.lib.json +17 -0
  244. package/tsconfig.lib.prod.json +10 -0
  245. package/tsconfig.spec.json +9 -0
  246. package/fesm2022/tacdaed-fragments.mjs +0 -8928
  247. package/fesm2022/tacdaed-fragments.mjs.map +0 -1
  248. package/index.d.ts +0 -3929
@@ -0,0 +1,410 @@
1
+ import { Component, ElementRef, HostListener, Input, OnInit, ViewChild } from '@angular/core';
2
+ import { NgClass } from '@angular/common';
3
+ import { InputBase } from '../input-base';
4
+ import { InputRequiredLabelPipe } from '../input.pipe';
5
+ import { InputValidationComponent } from '../input-validation/input-validation.component';
6
+ import { DEFAULT_INPUT_SLIDER_ERROR_MESSAGES, DEFAULT_INPUT_SLIDER_WARNING_MESSAGES } from '../input-consts';
7
+ import { InputChoiceStyleType, InputSliderSize } from '../input-type';
8
+
9
+ type InputSliderValue = number | [number, number];
10
+ type SliderHandle = 'single' | 'min' | 'max';
11
+
12
+ @Component({
13
+ selector: 'frg-input-slider',
14
+ imports: [InputRequiredLabelPipe, InputValidationComponent, NgClass],
15
+ templateUrl: './input-slider.component.html',
16
+ styleUrl: './input-slider.component.scss',
17
+ })
18
+ export class InputSliderComponent extends InputBase<InputSliderValue> implements OnInit {
19
+ /**
20
+ * @inheritdoc
21
+ */
22
+ @Input() public override label: string = '';
23
+ /**
24
+ * @inheritdoc
25
+ */
26
+ @Input() public override required: boolean = false;
27
+ /**
28
+ * @inheritdoc
29
+ */
30
+ @Input() public override showValidation: boolean = true;
31
+ /**
32
+ * @inheritdoc
33
+ */
34
+ @Input() public override errorMessages: Record<string, string> = {};
35
+ /**
36
+ * @inheritdoc
37
+ */
38
+ @Input() public override warningMessages: Record<string, string> = {};
39
+
40
+ /**
41
+ * Minimum slider value.
42
+ */
43
+ @Input() public min: number = 0;
44
+ /**
45
+ * Maximum slider value.
46
+ */
47
+ @Input() public max: number = 100;
48
+ /**
49
+ * Step interval for the slider.
50
+ */
51
+ @Input() public step: number = 1;
52
+ /**
53
+ * Enable dual-handle range mode.
54
+ */
55
+ @Input() public range: boolean = false;
56
+ /**
57
+ * Show tick marks along the track.
58
+ */
59
+ @Input() public showTicks: boolean = false;
60
+ /**
61
+ * Optional tick interval (defaults to step).
62
+ */
63
+ @Input() public tickStep: number | null = null;
64
+ /**
65
+ * Maximum number of ticks to render.
66
+ */
67
+ @Input() public maxTicks: number = 50;
68
+ /**
69
+ * Show tooltip on hover/drag.
70
+ */
71
+ @Input() public showTooltip: boolean = true;
72
+ /**
73
+ * Show numeric value(s) above the slider.
74
+ */
75
+ @Input() public showValue: boolean = false;
76
+ /**
77
+ * Slider size.
78
+ */
79
+ @Input() public size: InputSliderSize = 'medium';
80
+ /**
81
+ * Slider color style.
82
+ */
83
+ @Input() public styleType: InputChoiceStyleType = 'primary';
84
+
85
+ @ViewChild('track', { static: true }) private track!: ElementRef<HTMLDivElement>;
86
+
87
+ private currentValue: number = 0;
88
+ private currentRange: [number, number] = [0, 0];
89
+ private dragging: boolean = false;
90
+ private activeHandle: SliderHandle = 'single';
91
+ private activePointerId: number | null = null;
92
+
93
+ /** Internal store for warnings */
94
+ private warnings: Record<string, boolean> = {};
95
+
96
+ public override ngOnInit(): void {
97
+ super.ngOnInit();
98
+ this.syncFromValue();
99
+ }
100
+
101
+ protected updateView(_value: InputSliderValue | null): void {
102
+ this.syncFromValue();
103
+ }
104
+
105
+ protected updateDisabledState(_isDisabled: boolean): void {
106
+ // Handled by Angular binding
107
+ }
108
+
109
+ protected override get errorList(): string[] {
110
+ if (!this.control?.errors) return [];
111
+ return Object.keys(this.control.errors).map(key => {
112
+ return this.errorMessages[key] ?? DEFAULT_INPUT_SLIDER_ERROR_MESSAGES[key] ?? 'Invalid field.';
113
+ });
114
+ }
115
+
116
+ protected override get warningList(): string[] {
117
+ return Object.keys(this.warnings).map(key => {
118
+ return (
119
+ this.warningMessages[key] ??
120
+ DEFAULT_INPUT_SLIDER_WARNING_MESSAGES[key] ??
121
+ ''
122
+ );
123
+ });
124
+ }
125
+
126
+ protected get hasWarning(): boolean {
127
+ return this.warningList.length > 0;
128
+ }
129
+
130
+ protected get displayValue(): string {
131
+ return this.formatValue(this.currentValue);
132
+ }
133
+
134
+ protected get displayRangeMin(): string {
135
+ return this.formatValue(this.currentRange[0]);
136
+ }
137
+
138
+ protected get displayRangeMax(): string {
139
+ return this.formatValue(this.currentRange[1]);
140
+ }
141
+
142
+ protected get rangeMinValue(): number {
143
+ return this.currentRange[0];
144
+ }
145
+
146
+ protected get rangeMaxValue(): number {
147
+ return this.currentRange[1];
148
+ }
149
+
150
+ protected get singleValue(): number {
151
+ return this.currentValue;
152
+ }
153
+
154
+ protected get minPercent(): number {
155
+ return this.valueToPercent(this.currentRange[0]);
156
+ }
157
+
158
+ protected get maxPercent(): number {
159
+ return this.valueToPercent(this.currentRange[1]);
160
+ }
161
+
162
+ protected get singlePercent(): number {
163
+ return this.valueToPercent(this.currentValue);
164
+ }
165
+
166
+ protected get rangeWidth(): number {
167
+ return this.maxPercent - this.minPercent;
168
+ }
169
+
170
+ protected get showRange(): boolean {
171
+ return this.range;
172
+ }
173
+
174
+ protected get ticks(): number[] {
175
+ if (!this.showTicks) return [];
176
+ const step = this.tickStep ?? this.step;
177
+ if (step <= 0 || this.max <= this.min) return [];
178
+
179
+ const count = Math.floor((this.max - this.min) / step);
180
+ if (count <= this.maxTicks) {
181
+ return Array.from({ length: count + 1 }, (_, i) => this.min + i * step);
182
+ }
183
+
184
+ const interval = (this.max - this.min) / this.maxTicks;
185
+ return Array.from({ length: this.maxTicks + 1 }, (_, i) => this.min + i * interval);
186
+ }
187
+
188
+ protected get sliderClasses(): Record<string, boolean> {
189
+ return {
190
+ [`frg-slider--${this.size}`]: true,
191
+ [`frg-slider--${this.styleType}`]: true,
192
+ };
193
+ }
194
+
195
+ protected isHandleActive(handle: SliderHandle): boolean {
196
+ return this.dragging && this.activeHandle === handle;
197
+ }
198
+
199
+ protected onTrackPointerDown(event: PointerEvent): void {
200
+ if (this.disabled) return;
201
+ event.preventDefault();
202
+
203
+ const value = this.valueFromPointer(event);
204
+ if (this.range) {
205
+ const distMin = Math.abs(value - this.currentRange[0]);
206
+ const distMax = Math.abs(value - this.currentRange[1]);
207
+ this.activeHandle = distMin <= distMax ? 'min' : 'max';
208
+ this.setRangeValue(this.activeHandle, value, true);
209
+ } else {
210
+ this.activeHandle = 'single';
211
+ this.setSingleValue(value, true);
212
+ }
213
+
214
+ this.startDragging(event);
215
+ }
216
+
217
+ protected onHandlePointerDown(event: PointerEvent, handle: SliderHandle): void {
218
+ if (this.disabled) return;
219
+ event.preventDefault();
220
+ event.stopPropagation();
221
+
222
+ this.activeHandle = handle;
223
+ this.startDragging(event);
224
+ }
225
+
226
+ protected onHandleKeydown(event: KeyboardEvent, handle: SliderHandle): void {
227
+ if (this.disabled) return;
228
+
229
+ const step = this.safeStep;
230
+ let nextValue: number | null = null;
231
+
232
+ switch (event.key) {
233
+ case 'ArrowLeft':
234
+ case 'ArrowDown':
235
+ nextValue = this.getHandleValue(handle) - step;
236
+ break;
237
+ case 'ArrowRight':
238
+ case 'ArrowUp':
239
+ nextValue = this.getHandleValue(handle) + step;
240
+ break;
241
+ case 'PageDown':
242
+ nextValue = this.getHandleValue(handle) - step * 10;
243
+ break;
244
+ case 'PageUp':
245
+ nextValue = this.getHandleValue(handle) + step * 10;
246
+ break;
247
+ case 'Home':
248
+ nextValue = this.min;
249
+ break;
250
+ case 'End':
251
+ nextValue = this.max;
252
+ break;
253
+ default:
254
+ return;
255
+ }
256
+
257
+ event.preventDefault();
258
+ const snapped = this.snapValue(nextValue);
259
+
260
+ if (this.range) {
261
+ this.setRangeValue(handle, snapped, true);
262
+ } else {
263
+ this.setSingleValue(snapped, true);
264
+ }
265
+ }
266
+
267
+ @HostListener('document:pointermove', ['$event'])
268
+ protected onDocumentPointerMove(event: PointerEvent): void {
269
+ if (!this.dragging || (this.activePointerId !== null && event.pointerId !== this.activePointerId)) return;
270
+ event.preventDefault();
271
+
272
+ const value = this.valueFromPointer(event);
273
+ if (this.range) {
274
+ this.setRangeValue(this.activeHandle, value, true);
275
+ } else {
276
+ this.setSingleValue(value, true);
277
+ }
278
+ }
279
+
280
+ @HostListener('document:pointerup', ['$event'])
281
+ protected onDocumentPointerUp(event: PointerEvent): void {
282
+ if (!this.dragging || (this.activePointerId !== null && event.pointerId !== this.activePointerId)) return;
283
+ event.preventDefault();
284
+
285
+ this.dragging = false;
286
+ this.activePointerId = null;
287
+ this.onTouched();
288
+ }
289
+
290
+ private syncFromValue(): void {
291
+ if (this.range) {
292
+ const next = this.normalizeRangeValue(this.value);
293
+ this.currentRange = next;
294
+ } else {
295
+ const next = this.normalizeSingleValue(this.value);
296
+ this.currentValue = next;
297
+ }
298
+ }
299
+
300
+ private normalizeSingleValue(value: InputSliderValue | null): number {
301
+ const raw = typeof value === 'number' ? value : Array.isArray(value) ? value[0] : this.min;
302
+ return this.snapValue(raw);
303
+ }
304
+
305
+ private normalizeRangeValue(value: InputSliderValue | null): [number, number] {
306
+ let start = this.min;
307
+ let end = this.max;
308
+
309
+ if (Array.isArray(value) && value.length === 2) {
310
+ start = value[0];
311
+ end = value[1];
312
+ } else if (typeof value === 'number') {
313
+ start = value;
314
+ end = this.max;
315
+ }
316
+
317
+ start = this.snapValue(start);
318
+ end = this.snapValue(end);
319
+
320
+ if (start > end) {
321
+ return [end, start];
322
+ }
323
+
324
+ return [start, end];
325
+ }
326
+
327
+ private setSingleValue(value: number, emit: boolean): void {
328
+ const next = this.snapValue(value);
329
+ if (next === this.currentValue) return;
330
+
331
+ this.currentValue = next;
332
+ this.value = next;
333
+ if (emit) {
334
+ this.onChange(this.value);
335
+ this.onTouched();
336
+ }
337
+ }
338
+
339
+ private setRangeValue(handle: SliderHandle, value: number, emit: boolean): void {
340
+ let [start, end] = this.currentRange;
341
+ const next = this.snapValue(value);
342
+
343
+ if (handle === 'min') {
344
+ start = Math.min(next, end);
345
+ } else if (handle === 'max') {
346
+ end = Math.max(next, start);
347
+ }
348
+
349
+ if (start === this.currentRange[0] && end === this.currentRange[1]) return;
350
+
351
+ this.currentRange = [start, end];
352
+ this.value = [start, end];
353
+ if (emit) {
354
+ this.onChange(this.value);
355
+ this.onTouched();
356
+ }
357
+ }
358
+
359
+ private startDragging(event: PointerEvent): void {
360
+ this.dragging = true;
361
+ this.activePointerId = event.pointerId ?? null;
362
+ }
363
+
364
+ private valueFromPointer(event: PointerEvent): number {
365
+ const rect = this.track.nativeElement.getBoundingClientRect();
366
+ const ratio = (event.clientX - rect.left) / rect.width;
367
+ const clamped = Math.min(1, Math.max(0, ratio));
368
+ return this.min + clamped * (this.max - this.min);
369
+ }
370
+
371
+ protected valueToPercent(value: number): number {
372
+ if (this.max === this.min) return 0;
373
+ return ((value - this.min) / (this.max - this.min)) * 100;
374
+ }
375
+
376
+ private snapValue(value: number): number {
377
+ const clamped = Math.min(this.max, Math.max(this.min, value));
378
+ const step = this.safeStep;
379
+ const steps = Math.round((clamped - this.min) / step);
380
+ const snapped = this.min + steps * step;
381
+ return this.roundToPrecision(snapped);
382
+ }
383
+
384
+ private roundToPrecision(value: number): number {
385
+ const precision = this.stepPrecision;
386
+ if (precision <= 0) return Math.round(value);
387
+ return Number(value.toFixed(precision));
388
+ }
389
+
390
+ private formatValue(value: number): string {
391
+ const precision = this.stepPrecision;
392
+ if (precision <= 0) return value.toString();
393
+ return value.toFixed(precision);
394
+ }
395
+
396
+ private get safeStep(): number {
397
+ return this.step > 0 ? this.step : 1;
398
+ }
399
+
400
+ private get stepPrecision(): number {
401
+ const text = this.safeStep.toString();
402
+ const index = text.indexOf('.');
403
+ return index >= 0 ? text.length - index - 1 : 0;
404
+ }
405
+
406
+ private getHandleValue(handle: SliderHandle): number {
407
+ if (!this.range) return this.currentValue;
408
+ return handle === 'min' ? this.currentRange[0] : this.currentRange[1];
409
+ }
410
+ }
@@ -0,0 +1,67 @@
1
+ import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
2
+
3
+ export function strictEmailValidator(): ValidatorFn {
4
+ return (control: AbstractControl): ValidationErrors | null => {
5
+ const value = control.value;
6
+ if (!value) {
7
+ return null;
8
+ }
9
+ const strictPattern = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
10
+ return strictPattern.test(value) ? null : { strictEmail: true };
11
+ };
12
+ }
13
+
14
+ //#region [Tel validators]
15
+ export function phoneNumberValidator(): ValidatorFn {
16
+ return (control: AbstractControl): ValidationErrors | null => {
17
+ const value = control.value;
18
+
19
+ if (!value) {
20
+ return null;
21
+ }
22
+
23
+ const pattern = /^[+\d\s-]{7,15}$/;
24
+ return pattern.test(value) ? null : { phone: true };
25
+ };
26
+ }
27
+
28
+ export function strictPhoneNumberValidator(): ValidatorFn {
29
+ return (control: AbstractControl): ValidationErrors | null => {
30
+ const value = control.value?.trim();
31
+
32
+ if (!value) {
33
+ return null;
34
+ }
35
+
36
+ const strictTelPattern = /^\+[1-9]\d{7,14}$/;
37
+ return strictTelPattern.test(value) ? null : { strictPhone: true };
38
+ };
39
+ }
40
+ //#endregion
41
+
42
+ //#region [Url validator]
43
+ export function urlValidator(): ValidatorFn {
44
+ return (control: AbstractControl): ValidationErrors | null => {
45
+ const value = control.value;
46
+
47
+ if (!value) {
48
+ return null;
49
+ }
50
+ const pattern = /^(https?:\/\/)?([\w-]+(\.[\w-]+)+)([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?$/;
51
+ return pattern.test(control.value) ? null : { url: true };
52
+ };
53
+ }
54
+
55
+ export function strictUrlValidator(): ValidatorFn {
56
+ return (control: AbstractControl): ValidationErrors | null => {
57
+ const value = control.value;
58
+
59
+ if (!value) {
60
+ return null;
61
+ }
62
+
63
+ const pattern = /^(https?:\/\/)([\w-]+(\.[\w-]+)+)?$/;
64
+ return pattern.test(value) ? null : { strictUrl: true };
65
+ };
66
+ }
67
+ //#endregion
@@ -0,0 +1,71 @@
1
+ <div class="frg-input__wrapper"
2
+ [class.input-error]="hasError"
3
+ [class.input-warning]="hasWarning"
4
+ >
5
+ @if(label){
6
+ <label [for]="id">{{ label | inputRequiredLabel: required }}</label>
7
+ }
8
+
9
+ <input
10
+ [id]="id"
11
+ [type]="inputType"
12
+ [placeholder]="placeholder"
13
+ [required]="required"
14
+ [disabled]="disabled"
15
+ [value]="value"
16
+ (input)="onInput($event)"
17
+ (blur)="onBlur()"
18
+ />
19
+
20
+ @if(type === 'password') {
21
+ <ng-container *ngTemplateOutlet="passwordToggleTemplate"></ng-container>
22
+ }
23
+ @else if(type === 'email') {
24
+ <ng-container *ngTemplateOutlet="emailExtraTemplate"></ng-container>
25
+ }
26
+ @else if(type === 'tel') {
27
+ <ng-container *ngTemplateOutlet="phoneExtraTemplate"></ng-container>
28
+ }
29
+ @else if(type === 'url') {
30
+ <ng-container *ngTemplateOutlet="urlExtraTemplate"></ng-container>
31
+ }
32
+
33
+ </div>
34
+
35
+ @if(showValidation) {
36
+ <frg-input-validation
37
+ [errorList]="errorList"
38
+ [warningList]="warningList"
39
+ [isFormInvalid]="hasError"
40
+ >
41
+ </frg-input-validation>
42
+ }
43
+
44
+ <!-- Templates -->
45
+ <ng-template #passwordToggleTemplate>
46
+ <button type="button" class="frg-input__toggle-password" (click)="toggleShowPassword()">
47
+ @if(showPassword){
48
+ <span class="far fa-eye-slash"></span>
49
+ } @else {
50
+ <span class="far fa-eye"></span>
51
+ }
52
+ </button>
53
+ </ng-template>
54
+
55
+ <ng-template #emailExtraTemplate>
56
+ <div class="frg-input__email-container">
57
+ <span class="far fa-envelope"></span>
58
+ </div>
59
+ </ng-template>
60
+
61
+ <ng-template #phoneExtraTemplate>
62
+ <div class="frg-input__phone-container">
63
+ <span class="fas fa-mobile-screen"></span>
64
+ </div>
65
+ </ng-template>
66
+
67
+ <ng-template #urlExtraTemplate>
68
+ <div class="frg-input__url-container">
69
+ <span class="fas fa-link"></span>
70
+ </div>
71
+ </ng-template>
@@ -0,0 +1,118 @@
1
+ @use "sass:color";
2
+ @use './../../../../../assets/styles/scss/variables' as *;
3
+
4
+ :host {
5
+ display: block;
6
+
7
+ label {
8
+ display: flex;
9
+ font-size: $font-size-xs;
10
+ color: $input-text-color;
11
+ padding: $input-padding;
12
+ }
13
+
14
+ .frg-input {
15
+ font-family: $input-font-family;
16
+
17
+ &__wrapper {
18
+ position: relative;
19
+ display: inline-block;
20
+ width: 100%;
21
+
22
+ input {
23
+ padding: $input-padding;
24
+ border: none;
25
+ width: 100%;
26
+ border-bottom: 2px solid $input-border-color;
27
+ font-family: $input-font-family;
28
+ background: transparent;
29
+ transition: border-color 0.3s;
30
+
31
+ &:focus {
32
+ outline: none;
33
+ }
34
+
35
+ &:has(+ .frg-input__toggle-password) {
36
+ padding: 0.25rem 1.75rem 0.25rem 0.5rem;
37
+ }
38
+
39
+ &:has(+ .frg-input__email-container) {
40
+ padding: 0.25rem 1.75rem 0.25rem 0.5rem;
41
+ }
42
+
43
+ &:has(+ .frg-input__phone-container) {
44
+ padding: 0.25rem 1.75rem 0.25rem 0.5rem;
45
+ }
46
+
47
+ &:has(+ .frg-input__url-container) {
48
+ padding: 0.25rem 1.75rem 0.25rem 0.5rem;
49
+ }
50
+ }
51
+
52
+ &.input-error input {
53
+ border-bottom-color: $color-danger;
54
+ }
55
+
56
+ &.input-error label {
57
+ color: $color-danger;
58
+ }
59
+
60
+ &::before {
61
+ content: "";
62
+ position: absolute;
63
+ bottom: 0;
64
+ left: -50%;
65
+ width: 0;
66
+ height: 0.125rem;
67
+ background: $input-focus-border-color;
68
+ transition: width 0.3s ease, left 0.3s ease;
69
+ }
70
+
71
+ &:has(input:focus)::before {
72
+ width: 100%;
73
+ left: 0;
74
+ }
75
+
76
+ &.input-error::before {
77
+ width: 100%;
78
+ left: 0;
79
+ }
80
+
81
+ &::after {
82
+ content: "";
83
+ position: absolute;
84
+ bottom: 0;
85
+ right: -50%;
86
+ width: 0;
87
+ height: 0.125rem;
88
+ background: $color-danger;
89
+ transition: width 0.3s ease, right 0.3s ease;
90
+ }
91
+
92
+ &.input-error::after {
93
+ background: $color-danger;
94
+ width: 100%;
95
+ right: 0;
96
+ }
97
+
98
+ }
99
+
100
+ &__toggle-password,
101
+ &__email-container,
102
+ &__phone-container,
103
+ &__url-container {
104
+ position: absolute;
105
+ top: 50%;
106
+ right: 0.25rem;
107
+ background: transparent;
108
+ border: none;
109
+ font-size: 1rem;
110
+ color: $input-text-color;
111
+ padding: 0;
112
+ }
113
+
114
+ &__toggle-password {
115
+ cursor: pointer;
116
+ }
117
+ }
118
+ }