commons-shared-web-ui 0.0.62 → 0.0.64

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 (222) hide show
  1. package/fesm2022/commons-shared-web-ui.mjs +16368 -0
  2. package/fesm2022/commons-shared-web-ui.mjs.map +1 -0
  3. package/index.d.ts +5077 -0
  4. package/package.json +34 -53
  5. package/.claude/settings.local.json +0 -10
  6. package/documentation/alert.md +0 -123
  7. package/documentation/button-dropdown.md +0 -126
  8. package/documentation/button.md +0 -184
  9. package/documentation/cards-usage-guidelines.md +0 -131
  10. package/documentation/configurable-form.md +0 -605
  11. package/documentation/confirmation-modal.md +0 -250
  12. package/documentation/filter-sidebar.md +0 -178
  13. package/documentation/filter-table-selector.md +0 -228
  14. package/documentation/form-builder.md +0 -599
  15. package/documentation/form-components.md +0 -384
  16. package/documentation/form-field-configuration.md +0 -250
  17. package/documentation/nav.md +0 -427
  18. package/documentation/pagination.md +0 -181
  19. package/documentation/side-nav-documentation.md +0 -169
  20. package/documentation/smart-form.md +0 -2819
  21. package/documentation/smart-table.md +0 -1297
  22. package/documentation/snackbar.md +0 -118
  23. package/documentation/style-externalization.md +0 -88
  24. package/documentation/summary-card.md +0 -279
  25. package/documentation/table-column-configuration.md +0 -221
  26. package/documentation/time-picker.md +0 -274
  27. package/ng-package.json +0 -30
  28. package/src/lib/modules/alert/alert.models.ts +0 -6
  29. package/src/lib/modules/alert/alert.module.ts +0 -16
  30. package/src/lib/modules/alert/components/alert/alert.component.html +0 -27
  31. package/src/lib/modules/alert/components/alert/alert.component.scss +0 -92
  32. package/src/lib/modules/alert/components/alert/alert.component.ts +0 -81
  33. package/src/lib/modules/button/button.models.ts +0 -13
  34. package/src/lib/modules/button/button.module.ts +0 -16
  35. package/src/lib/modules/button/components/button/button.component.html +0 -22
  36. package/src/lib/modules/button/components/button/button.component.scss +0 -92
  37. package/src/lib/modules/button/components/button/button.component.ts +0 -67
  38. package/src/lib/modules/button-dropdown/button-dropdown.models.ts +0 -26
  39. package/src/lib/modules/button-dropdown/button-dropdown.module.ts +0 -22
  40. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.html +0 -41
  41. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.scss +0 -135
  42. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.ts +0 -160
  43. package/src/lib/modules/configurable-form/component/configurable-form.component.html +0 -294
  44. package/src/lib/modules/configurable-form/component/configurable-form.component.scss +0 -503
  45. package/src/lib/modules/configurable-form/component/configurable-form.component.ts +0 -628
  46. package/src/lib/modules/configurable-form/configurable-form.examples.ts +0 -154
  47. package/src/lib/modules/configurable-form/configurable-form.model.ts +0 -131
  48. package/src/lib/modules/configurable-form/configurable-form.module.ts +0 -19
  49. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.html +0 -77
  50. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.scss +0 -395
  51. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.ts +0 -266
  52. package/src/lib/modules/confirmation-modal/confirmation-modal.models.ts +0 -71
  53. package/src/lib/modules/confirmation-modal/confirmation-modal.module.ts +0 -20
  54. package/src/lib/modules/filter/components/filter/filter.component.html +0 -131
  55. package/src/lib/modules/filter/components/filter/filter.component.scss +0 -245
  56. package/src/lib/modules/filter/components/filter/filter.component.ts +0 -216
  57. package/src/lib/modules/filter/filter.models.ts +0 -88
  58. package/src/lib/modules/filter/filter.module.ts +0 -24
  59. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.html +0 -112
  60. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.scss +0 -186
  61. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.ts +0 -163
  62. package/src/lib/modules/filter-sidebar/filter-sidebar.models.ts +0 -95
  63. package/src/lib/modules/filter-sidebar/filter-sidebar.module.ts +0 -24
  64. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.html +0 -73
  65. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.scss +0 -321
  66. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.ts +0 -361
  67. package/src/lib/modules/filter-table-selector/filter-table-selector.models.ts +0 -91
  68. package/src/lib/modules/filter-table-selector/filter-table-selector.module.ts +0 -22
  69. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.html +0 -63
  70. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.scss +0 -496
  71. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.ts +0 -445
  72. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.html +0 -75
  73. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.scss +0 -210
  74. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.ts +0 -55
  75. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.html +0 -25
  76. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.scss +0 -82
  77. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.ts +0 -95
  78. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.html +0 -20
  79. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.scss +0 -37
  80. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.ts +0 -94
  81. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.html +0 -46
  82. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.scss +0 -102
  83. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.ts +0 -50
  84. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.html +0 -35
  85. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.scss +0 -67
  86. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.ts +0 -34
  87. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.html +0 -68
  88. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.scss +0 -113
  89. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.ts +0 -74
  90. package/src/lib/modules/form-builder/configs/field-type-schema.map.ts +0 -533
  91. package/src/lib/modules/form-builder/form-builder.module.ts +0 -36
  92. package/src/lib/modules/form-builder/index.ts +0 -9
  93. package/src/lib/modules/form-builder/models/builder.models.ts +0 -7
  94. package/src/lib/modules/form-builder/models/field-configurator.models.ts +0 -38
  95. package/src/lib/modules/form-builder/models/field-selection.models.ts +0 -51
  96. package/src/lib/modules/form-builder/services/field-configurator.service.ts +0 -258
  97. package/src/lib/modules/form-builder/services/field-selection.service.ts +0 -299
  98. package/src/lib/modules/form-builder/services/form-schema-tree.service.ts +0 -670
  99. package/src/lib/modules/form-builder/tokens/builder.tokens.ts +0 -10
  100. package/src/lib/modules/form-builder/utils/constants.ts +0 -43
  101. package/src/lib/modules/form-components/components/checkbox/checkbox.component.html +0 -29
  102. package/src/lib/modules/form-components/components/checkbox/checkbox.component.scss +0 -111
  103. package/src/lib/modules/form-components/components/checkbox/checkbox.component.ts +0 -207
  104. package/src/lib/modules/form-components/components/checkbox/checkbox.models.ts +0 -35
  105. package/src/lib/modules/form-components/components/datepicker/datepicker.component.html +0 -42
  106. package/src/lib/modules/form-components/components/datepicker/datepicker.component.scss +0 -115
  107. package/src/lib/modules/form-components/components/datepicker/datepicker.component.ts +0 -267
  108. package/src/lib/modules/form-components/components/datepicker/datepicker.models.ts +0 -45
  109. package/src/lib/modules/form-components/components/dropdown/dropdown.component.html +0 -74
  110. package/src/lib/modules/form-components/components/dropdown/dropdown.component.scss +0 -252
  111. package/src/lib/modules/form-components/components/dropdown/dropdown.component.ts +0 -377
  112. package/src/lib/modules/form-components/components/dropdown/dropdown.models.ts +0 -53
  113. package/src/lib/modules/form-components/components/input/input.component.html +0 -51
  114. package/src/lib/modules/form-components/components/input/input.component.scss +0 -128
  115. package/src/lib/modules/form-components/components/input/input.component.ts +0 -250
  116. package/src/lib/modules/form-components/components/input/input.models.ts +0 -55
  117. package/src/lib/modules/form-components/components/radio/radio.component.html +0 -22
  118. package/src/lib/modules/form-components/components/radio/radio.component.scss +0 -107
  119. package/src/lib/modules/form-components/components/radio/radio.component.ts +0 -181
  120. package/src/lib/modules/form-components/components/radio/radio.models.ts +0 -39
  121. package/src/lib/modules/form-components/components/search/search.component.html +0 -15
  122. package/src/lib/modules/form-components/components/search/search.component.scss +0 -87
  123. package/src/lib/modules/form-components/components/search/search.component.ts +0 -213
  124. package/src/lib/modules/form-components/components/search/search.models.ts +0 -40
  125. package/src/lib/modules/form-components/components/toggle/toggle.component.html +0 -15
  126. package/src/lib/modules/form-components/components/toggle/toggle.component.scss +0 -81
  127. package/src/lib/modules/form-components/components/toggle/toggle.component.ts +0 -166
  128. package/src/lib/modules/form-components/components/toggle/toggle.models.ts +0 -27
  129. package/src/lib/modules/form-components/directives/click-outside.directive.ts +0 -22
  130. package/src/lib/modules/form-components/form-components.module.ts +0 -42
  131. package/src/lib/modules/form-field-configuration/components/_ffc-controls.scss +0 -89
  132. package/src/lib/modules/form-field-configuration/components/config-field-node/config-field-node.component.html +0 -68
  133. package/src/lib/modules/form-field-configuration/components/config-field-node/config-field-node.component.scss +0 -73
  134. package/src/lib/modules/form-field-configuration/components/config-field-node/config-field-node.component.ts +0 -34
  135. package/src/lib/modules/form-field-configuration/components/config-section-node/config-section-node.component.html +0 -78
  136. package/src/lib/modules/form-field-configuration/components/config-section-node/config-section-node.component.scss +0 -83
  137. package/src/lib/modules/form-field-configuration/components/config-section-node/config-section-node.component.ts +0 -94
  138. package/src/lib/modules/form-field-configuration/components/form-field-configuration/form-field-configuration.component.html +0 -38
  139. package/src/lib/modules/form-field-configuration/components/form-field-configuration/form-field-configuration.component.scss +0 -42
  140. package/src/lib/modules/form-field-configuration/components/form-field-configuration/form-field-configuration.component.ts +0 -92
  141. package/src/lib/modules/form-field-configuration/form-field-configuration.module.ts +0 -23
  142. package/src/lib/modules/form-field-configuration/index.ts +0 -7
  143. package/src/lib/modules/form-field-configuration/models/field-configuration.models.ts +0 -62
  144. package/src/lib/modules/form-field-configuration/services/config-schema-tree.service.ts +0 -159
  145. package/src/lib/modules/form-field-configuration/services/field-configuration.service.ts +0 -228
  146. package/src/lib/modules/material/material.module.ts +0 -94
  147. package/src/lib/modules/nav/components/nav/nav.component.html +0 -34
  148. package/src/lib/modules/nav/components/nav/nav.component.scss +0 -171
  149. package/src/lib/modules/nav/components/nav/nav.component.ts +0 -82
  150. package/src/lib/modules/nav/nav.models.ts +0 -31
  151. package/src/lib/modules/nav/nav.module.ts +0 -17
  152. package/src/lib/modules/pagination/components/pagination/pagination.component.html +0 -52
  153. package/src/lib/modules/pagination/components/pagination/pagination.component.scss +0 -155
  154. package/src/lib/modules/pagination/components/pagination/pagination.component.ts +0 -109
  155. package/src/lib/modules/pagination/pagination.module.ts +0 -17
  156. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.html +0 -56
  157. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.scss +0 -342
  158. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.ts +0 -135
  159. package/src/lib/modules/side-nav/side-nav.models.ts +0 -38
  160. package/src/lib/modules/side-nav/side-nav.module.ts +0 -16
  161. package/src/lib/modules/smart-form/components/form-field/form-field.component.html +0 -1379
  162. package/src/lib/modules/smart-form/components/form-field/form-field.component.scss +0 -2255
  163. package/src/lib/modules/smart-form/components/form-field/form-field.component.ts +0 -3174
  164. package/src/lib/modules/smart-form/components/form-section/form-section.component.html +0 -67
  165. package/src/lib/modules/smart-form/components/form-section/form-section.component.scss +0 -209
  166. package/src/lib/modules/smart-form/components/form-section/form-section.component.ts +0 -142
  167. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.html +0 -253
  168. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.scss +0 -689
  169. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.ts +0 -1134
  170. package/src/lib/modules/smart-form/index.ts +0 -10
  171. package/src/lib/modules/smart-form/models/form-schema.model.ts +0 -803
  172. package/src/lib/modules/smart-form/models/hierarchy-config.model.ts +0 -22
  173. package/src/lib/modules/smart-form/services/expression.service.ts +0 -75
  174. package/src/lib/modules/smart-form/services/smart-form-controller.service.ts +0 -67
  175. package/src/lib/modules/smart-form/smart-form.examples.ts +0 -1324
  176. package/src/lib/modules/smart-form/smart-form.module.ts +0 -40
  177. package/src/lib/modules/smart-form/utils/translation.utils.ts +0 -82
  178. package/src/lib/modules/smart-form/utils/trusted-url.pipe.ts +0 -25
  179. package/src/lib/modules/smart-form/utils/validation.utils.ts +0 -98
  180. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.html +0 -283
  181. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.scss +0 -685
  182. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.ts +0 -1219
  183. package/src/lib/modules/smart-table/models/table-config.model.ts +0 -247
  184. package/src/lib/modules/smart-table/smart-table.module.ts +0 -30
  185. package/src/lib/modules/smart-table/utils/safe-html.pipe.ts +0 -28
  186. package/src/lib/modules/smart-table/utils/smart-table.utils.ts +0 -18
  187. package/src/lib/modules/snackbar/components/snackbar.component.html +0 -41
  188. package/src/lib/modules/snackbar/components/snackbar.component.scss +0 -99
  189. package/src/lib/modules/snackbar/components/snackbar.component.ts +0 -18
  190. package/src/lib/modules/snackbar/models/snackbar.models.ts +0 -10
  191. package/src/lib/modules/snackbar/services/snackbar.service.ts +0 -40
  192. package/src/lib/modules/snackbar/snackbar.module.ts +0 -11
  193. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.html +0 -47
  194. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.scss +0 -199
  195. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.ts +0 -126
  196. package/src/lib/modules/summary-card/summary-card.module.ts +0 -18
  197. package/src/lib/modules/table-column-configuration/components/_tcc-controls.scss +0 -53
  198. package/src/lib/modules/table-column-configuration/components/config-column-node/config-column-node.component.html +0 -47
  199. package/src/lib/modules/table-column-configuration/components/config-column-node/config-column-node.component.scss +0 -50
  200. package/src/lib/modules/table-column-configuration/components/config-column-node/config-column-node.component.ts +0 -33
  201. package/src/lib/modules/table-column-configuration/components/table-column-configuration/table-column-configuration.component.html +0 -30
  202. package/src/lib/modules/table-column-configuration/components/table-column-configuration/table-column-configuration.component.scss +0 -36
  203. package/src/lib/modules/table-column-configuration/components/table-column-configuration/table-column-configuration.component.ts +0 -78
  204. package/src/lib/modules/table-column-configuration/index.ts +0 -5
  205. package/src/lib/modules/table-column-configuration/models/table-column-configuration.models.ts +0 -20
  206. package/src/lib/modules/table-column-configuration/services/table-column-configuration.service.ts +0 -77
  207. package/src/lib/modules/table-column-configuration/table-column-configuration.module.ts +0 -21
  208. package/src/lib/modules/time-picker/components/time-picker/time-picker.component.html +0 -37
  209. package/src/lib/modules/time-picker/components/time-picker/time-picker.component.scss +0 -102
  210. package/src/lib/modules/time-picker/components/time-picker/time-picker.component.ts +0 -178
  211. package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.html +0 -78
  212. package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.scss +0 -226
  213. package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.ts +0 -595
  214. package/src/lib/modules/time-picker/models/time-picker.models.ts +0 -49
  215. package/src/lib/modules/time-picker/time-picker.module.ts +0 -23
  216. package/src/lib/shared-ui.module.ts +0 -55
  217. package/src/lib/utils/constants.ts +0 -11
  218. package/src/lib/utils/storage.utils.ts +0 -37
  219. package/src/lib/utils/string.utils.ts +0 -23
  220. package/src/lib/utils/translation.utils.ts +0 -87
  221. package/src/public-api.ts +0 -127
  222. package/tsconfig.lib.json +0 -15
@@ -1,595 +0,0 @@
1
- import { Component, Input, Output, EventEmitter, OnInit, AfterViewInit, OnDestroy, ViewChild, ElementRef, NgZone, OnChanges, SimpleChanges } from '@angular/core';
2
- import { TimeMode, TimePickerLabels } from '../../models/time-picker.models';
3
-
4
- type WheelType = 'hour' | 'minute' | 'period';
5
-
6
- @Component({
7
- selector: 'lib-time-wheel-panel',
8
- templateUrl: './time-wheel-panel.component.html',
9
- styleUrls: ['./time-wheel-panel.component.scss'],
10
- standalone: false
11
- })
12
- export class TimeWheelPanelComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
13
- @Input() mode: TimeMode = '12';
14
- @Input() value: string = '';
15
- @Input() labels?: TimePickerLabels;
16
- @Input() minuteStep: number = 0;
17
- @Input() minTime?: string; // "HH:mm" 24h
18
- @Input() maxTime?: string; // "HH:mm" 24h
19
-
20
- @Output() confirmed = new EventEmitter<string>();
21
- @Output() cancelled = new EventEmitter<void>();
22
-
23
- @ViewChild('hourWheel') hourWheel!: ElementRef<HTMLDivElement>;
24
- @ViewChild('minuteWheel') minuteWheel!: ElementRef<HTMLDivElement>;
25
- @ViewChild('periodWheel') periodWheel?: ElementRef<HTMLDivElement>;
26
-
27
- // ─── Geometry (single source of truth; keep in sync with SCSS) ───
28
- static readonly ITEM_HEIGHT = 36;
29
- static readonly VISIBLE_ROWS = 3;
30
- readonly ITEM_HEIGHT = TimeWheelPanelComponent.ITEM_HEIGHT;
31
- readonly SPACERS = (TimeWheelPanelComponent.VISIBLE_ROWS - 1) / 2; // leading == trailing
32
- readonly spacerRows: number[] = Array.from({ length: this.SPACERS }, (_, i) => i);
33
- private get containerHeight(): number {
34
- return TimeWheelPanelComponent.VISIBLE_ROWS * this.ITEM_HEIGHT;
35
- }
36
-
37
- hours: string[] = [];
38
- minutes: string[] = [];
39
- periods: string[] = ['AM', 'PM'];
40
-
41
- // How many times each list is repeated in the DOM for the infinite loop.
42
- // Computed per-list so one repeat band is always >= the viewport height.
43
- hourRepeats: number[] = [0, 1, 2];
44
- minuteRepeats: number[] = [0, 1, 2];
45
-
46
- selectedHour: string = '09';
47
- selectedMinute: string = '00';
48
- selectedPeriod: string = 'AM';
49
-
50
- disabledHours = new Set<string>();
51
- disabledMinutes = new Set<string>();
52
- disabledPeriods = new Set<string>();
53
-
54
- private isInitialScrollDone: boolean = false;
55
-
56
- private scrollListeners: Partial<Record<WheelType, () => void>> = {};
57
- private idleTimers: Partial<Record<WheelType, ReturnType<typeof setTimeout>>> = {};
58
- private rafIds: Partial<Record<WheelType, number>> = {};
59
-
60
- private static readonly IDLE_MS = 90;
61
-
62
- constructor(private zone: NgZone) {}
63
-
64
- ngOnInit(): void {
65
- this.generateHours();
66
- this.generateMinutes();
67
- this.parseInitialValue(this.value);
68
- this.computeConstraints();
69
- }
70
-
71
- ngOnChanges(changes: SimpleChanges): void {
72
- if (changes['mode'] || changes['minuteStep'] || changes['minTime'] || changes['maxTime']) {
73
- this.generateHours();
74
- this.generateMinutes();
75
- this.computeConstraints();
76
- if (this.isInitialScrollDone) {
77
- this.zone.runOutsideAngular(() => {
78
- this.scrollToValue('hour', this.selectedHour, false);
79
- this.scrollToValue('minute', this.selectedMinute, false);
80
- if (this.mode === '12') {
81
- this.scrollToValue('period', this.selectedPeriod, false);
82
- }
83
- });
84
- }
85
- }
86
- }
87
-
88
- ngAfterViewInit(): void {
89
- setTimeout(() => {
90
- this.scrollToValue('hour', this.selectedHour, false);
91
- this.scrollToValue('minute', this.selectedMinute, false);
92
- if (this.mode === '12') {
93
- this.scrollToValue('period', this.selectedPeriod, false);
94
- }
95
-
96
- this.updateWheelEffects(this.hourWheel.nativeElement);
97
- this.updateWheelEffects(this.minuteWheel.nativeElement);
98
- if (this.periodWheel) {
99
- this.updateWheelEffects(this.periodWheel.nativeElement);
100
- }
101
-
102
- this.isInitialScrollDone = true;
103
- }, 150);
104
-
105
- // Native scroll drives everything. On each scroll event we (rAF-throttled)
106
- // repaint the 3D wheel effect, and after the wheel goes idle we read the
107
- // settled value + do the seamless wrap-around reposition.
108
- this.zone.runOutsideAngular(() => {
109
- this.attachScroll('hour', this.hourWheel.nativeElement);
110
- this.attachScroll('minute', this.minuteWheel.nativeElement);
111
- if (this.periodWheel) {
112
- this.attachScroll('period', this.periodWheel.nativeElement);
113
- }
114
- });
115
- }
116
-
117
- ngOnDestroy(): void {
118
- const map: Partial<Record<WheelType, ElementRef<HTMLDivElement> | undefined>> = {
119
- hour: this.hourWheel,
120
- minute: this.minuteWheel,
121
- period: this.periodWheel
122
- };
123
- (Object.keys(this.scrollListeners) as WheelType[]).forEach(type => {
124
- const el = map[type]?.nativeElement;
125
- const listener = this.scrollListeners[type];
126
- if (el && listener) {
127
- el.removeEventListener('scroll', listener);
128
- }
129
- const raf = this.rafIds[type];
130
- if (raf) cancelAnimationFrame(raf);
131
- const timer = this.idleTimers[type];
132
- if (timer) clearTimeout(timer);
133
- });
134
- }
135
-
136
- private attachScroll(type: WheelType, element: HTMLElement): void {
137
- const listener = () => {
138
- // Throttle the visual repaint to one per frame.
139
- if (!this.rafIds[type]) {
140
- this.rafIds[type] = requestAnimationFrame(() => {
141
- this.rafIds[type] = undefined as unknown as number;
142
- this.updateWheelEffects(element);
143
- });
144
- }
145
-
146
- // Debounce the "settled" read.
147
- const existing = this.idleTimers[type];
148
- if (existing) clearTimeout(existing);
149
- this.idleTimers[type] = setTimeout(() => {
150
- this.onScrollIdle(type, element);
151
- }, TimeWheelPanelComponent.IDLE_MS);
152
- };
153
-
154
- this.scrollListeners[type] = listener;
155
- element.addEventListener('scroll', listener, { passive: true });
156
- }
157
-
158
- private generateHours(): void {
159
- if (this.mode === '12') {
160
- this.hours = Array.from({ length: 12 }, (_, i) => (i + 1).toString().padStart(2, '0'));
161
- } else {
162
- this.hours = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, '0'));
163
- }
164
- this.hourRepeats = this.buildRepeats(this.hours.length);
165
- }
166
-
167
- private generateMinutes(): void {
168
- const step = Math.max(1, this.minuteStep);
169
- this.minutes = [];
170
- for (let i = 0; i < 60; i += step) {
171
- this.minutes.push(i.toString().padStart(2, '0'));
172
- }
173
- this.minuteRepeats = this.buildRepeats(this.minutes.length);
174
- }
175
-
176
- // Odd repeat count so that one buffer band (N*ITEM_HEIGHT) on each side of the
177
- // central band is always >= the viewport height. Common case (N=12/24/60) → 3.
178
- private buildRepeats(n: number): number[] {
179
- const band = n * this.ITEM_HEIGHT;
180
- const count = Math.max(3, 2 * Math.ceil(this.containerHeight / band) + 1);
181
- return Array.from({ length: count }, (_, i) => i);
182
- }
183
-
184
- private centralBandStart(list: string[], repeats: number[]): number {
185
- // Index (in the repeated DOM list) of the first item of the central band.
186
- return Math.floor(repeats.length / 2) * list.length;
187
- }
188
-
189
- private parseInitialValue(valStr: string): void {
190
- if (!valStr) {
191
- this.setDefaultTime();
192
- return;
193
- }
194
-
195
- const twelveRegex = /^(\d{1,2}):(\d{2})\s*(AM|PM)$/i;
196
- const twentyFourRegex = /^(\d{1,2}):(\d{2})$/;
197
-
198
- let match = valStr.trim().match(twelveRegex);
199
- if (match) {
200
- const hh = match[1].padStart(2, '0');
201
- const mm = match[2];
202
- const period = match[3].toUpperCase();
203
-
204
- if (this.mode === '12') {
205
- this.selectedHour = hh;
206
- this.selectedMinute = this.findClosestMinute(mm);
207
- this.selectedPeriod = period;
208
- } else {
209
- // Convert to 24h
210
- let hNum = parseInt(hh, 10);
211
- if (period === 'PM' && hNum !== 12) hNum += 12;
212
- if (period === 'AM' && hNum === 12) hNum = 0;
213
- this.selectedHour = hNum.toString().padStart(2, '0');
214
- this.selectedMinute = this.findClosestMinute(mm);
215
- }
216
- return;
217
- }
218
-
219
- match = valStr.trim().match(twentyFourRegex);
220
- if (match) {
221
- const hh = match[1].padStart(2, '0');
222
- const mm = match[2];
223
-
224
- if (this.mode === '24') {
225
- this.selectedHour = hh;
226
- this.selectedMinute = this.findClosestMinute(mm);
227
- } else {
228
- // Convert to 12h
229
- let hNum = parseInt(hh, 10);
230
- const period = hNum >= 12 ? 'PM' : 'AM';
231
- if (hNum > 12) hNum -= 12;
232
- if (hNum === 0) hNum = 12;
233
- this.selectedHour = hNum.toString().padStart(2, '0');
234
- this.selectedMinute = this.findClosestMinute(mm);
235
- this.selectedPeriod = period;
236
- }
237
- return;
238
- }
239
-
240
- this.setDefaultTime();
241
- }
242
-
243
- private findClosestMinute(mmStr: string): string {
244
- const mmVal = parseInt(mmStr, 10);
245
- if (isNaN(mmVal)) return '00';
246
- let closest = this.minutes[0];
247
- let minDiff = 60;
248
- for (const m of this.minutes) {
249
- const mVal = parseInt(m, 10);
250
- const diff = Math.abs(mVal - mmVal);
251
- if (diff < minDiff) {
252
- minDiff = diff;
253
- closest = m;
254
- }
255
- }
256
- return closest;
257
- }
258
-
259
- private setDefaultTime(): void {
260
- if (this.mode === '12') {
261
- this.selectedHour = '09';
262
- this.selectedMinute = '00';
263
- this.selectedPeriod = 'AM';
264
- } else {
265
- this.selectedHour = '09';
266
- this.selectedMinute = '00';
267
- }
268
- }
269
-
270
- private toMinutes(h: number, m: number): number {
271
- return h * 60 + m;
272
- }
273
-
274
- private parseLimit(hhmm: string): { h: number; m: number } {
275
- const parts = hhmm.split(':');
276
- return {
277
- h: parseInt(parts[0], 10) || 0,
278
- m: parseInt(parts[1], 10) || 0
279
- };
280
- }
281
-
282
- private to24hrHour(displayHour: string, period: 'AM' | 'PM'): number {
283
- const h = parseInt(displayHour, 10);
284
- if (period === 'AM') {
285
- return h === 12 ? 0 : h;
286
- } else {
287
- return h === 12 ? 12 : h + 12;
288
- }
289
- }
290
-
291
- computeConstraints(): void {
292
- this.disabledHours.clear();
293
- this.disabledMinutes.clear();
294
- this.disabledPeriods.clear();
295
-
296
- if (!this.minTime && !this.maxTime) return;
297
-
298
- let minMin = 0;
299
- let maxMin = 23 * 60 + 59;
300
-
301
- if (this.minTime) {
302
- const parsed = this.parseLimit(this.minTime);
303
- minMin = this.toMinutes(parsed.h, parsed.m);
304
- }
305
- if (this.maxTime) {
306
- const parsed = this.parseLimit(this.maxTime);
307
- maxMin = this.toMinutes(parsed.h, parsed.m);
308
- }
309
-
310
- if (minMin > maxMin) {
311
- // Invalid config
312
- return;
313
- }
314
-
315
- if (this.mode === '24') {
316
- for (const h of this.hours) {
317
- const hNum = parseInt(h, 10);
318
- const hourStart = this.toMinutes(hNum, 0);
319
- const hourEnd = this.toMinutes(hNum, 59);
320
- if (hourEnd < minMin || hourStart > maxMin) {
321
- this.disabledHours.add(h);
322
- }
323
- }
324
-
325
- const selH = parseInt(this.selectedHour, 10);
326
- for (const m of this.minutes) {
327
- const mNum = parseInt(m, 10);
328
- const total = this.toMinutes(selH, mNum);
329
- if (total < minMin || total > maxMin) {
330
- this.disabledMinutes.add(m);
331
- }
332
- }
333
- return;
334
- }
335
-
336
- // 12-hour mode logic
337
- const amCoversAny = minMin < 12 * 60;
338
- const pmCoversAny = maxMin >= 12 * 60;
339
-
340
- if (!amCoversAny) this.disabledPeriods.add('AM');
341
- if (!pmCoversAny) this.disabledPeriods.add('PM');
342
-
343
- for (const h of this.hours) {
344
- const hNum = parseInt(h, 10);
345
-
346
- const h24_AM = hNum === 12 ? 0 : hNum;
347
- const amStart = this.toMinutes(h24_AM, 0);
348
- const amEnd = this.toMinutes(h24_AM, 59);
349
- const amValid = amEnd >= minMin && amStart <= maxMin && amCoversAny;
350
-
351
- const h24_PM = hNum === 12 ? 12 : hNum + 12;
352
- const pmStart = this.toMinutes(h24_PM, 0);
353
- const pmEnd = this.toMinutes(h24_PM, 59);
354
- const pmValid = pmEnd >= minMin && pmStart <= maxMin && pmCoversAny;
355
-
356
- if (this.selectedPeriod === 'AM' && !amValid) this.disabledHours.add(h);
357
- if (this.selectedPeriod === 'PM' && !pmValid) this.disabledHours.add(h);
358
- }
359
-
360
- const selH24 = this.to24hrHour(this.selectedHour, this.selectedPeriod as 'AM' | 'PM');
361
- for (const m of this.minutes) {
362
- const mNum = parseInt(m, 10);
363
- const total = this.toMinutes(selH24, mNum);
364
- if (total < minMin || total > maxMin) {
365
- this.disabledMinutes.add(m);
366
- }
367
- }
368
- }
369
-
370
- updateWheelEffects(element: HTMLElement): void {
371
- const scrollTop = element.scrollTop;
372
- const items = element.children;
373
-
374
- for (let i = 0; i < items.length; i++) {
375
- const item = items[i] as HTMLElement;
376
- if (item.classList.contains('cc-twp-spacer')) continue;
377
-
378
- const itemTop = (i - this.SPACERS) * this.ITEM_HEIGHT;
379
- const distance = Math.abs(itemTop - scrollTop);
380
-
381
- const maxDist = this.ITEM_HEIGHT * 2;
382
- const ratio = Math.max(0, 1 - distance / maxDist);
383
-
384
- // Flatter than the old drum look: gentle scale + opacity fade only.
385
- const scale = 0.85 + 0.15 * ratio;
386
- const opacity = 0.4 + 0.6 * ratio;
387
-
388
- item.style.transform = `scale(${scale}) translateZ(0)`;
389
- item.style.opacity = String(opacity);
390
- }
391
- }
392
-
393
- private listFor(type: WheelType): string[] {
394
- if (type === 'hour') return this.hours;
395
- if (type === 'minute') return this.minutes;
396
- return this.periods;
397
- }
398
-
399
- private repeatsFor(type: WheelType): number[] {
400
- if (type === 'hour') return this.hourRepeats;
401
- if (type === 'minute') return this.minuteRepeats;
402
- return [0];
403
- }
404
-
405
- private isDisabled(type: WheelType, val: string): boolean {
406
- if (type === 'hour') return this.disabledHours.has(val);
407
- if (type === 'minute') return this.disabledMinutes.has(val);
408
- return this.disabledPeriods.has(val);
409
- }
410
-
411
- // Called after native inertial scrolling settles.
412
- private onScrollIdle(type: WheelType, element: HTMLElement): void {
413
- if (!this.isInitialScrollDone) return;
414
-
415
- const list = this.listFor(type);
416
- const N = list.length;
417
- const looping = type === 'hour' || type === 'minute';
418
-
419
- // 1. Seamless wrap-around: keep the resting position inside the central band.
420
- if (looping) {
421
- const band = N * this.ITEM_HEIGHT;
422
- const start = this.centralBandStart(list, this.repeatsFor(type)) * this.ITEM_HEIGHT;
423
- const end = start + band;
424
- if (element.scrollTop < start || element.scrollTop >= end) {
425
- const originalScrollBehavior = element.style.scrollBehavior;
426
- element.style.scrollBehavior = 'auto';
427
-
428
- if (element.scrollTop < start) {
429
- element.scrollTop += band;
430
- } else {
431
- element.scrollTop -= band;
432
- }
433
-
434
- // Force layout reflow
435
- const _ = element.scrollTop;
436
- element.style.scrollBehavior = originalScrollBehavior;
437
- }
438
- }
439
-
440
- // 2. Read the settled value.
441
- let index = Math.round(element.scrollTop / this.ITEM_HEIGHT);
442
- let origIndex = looping ? ((index % N) + N) % N : Math.max(0, Math.min(N - 1, index));
443
- let val = list[origIndex];
444
-
445
- // 3. If it landed on a disabled value, snap to the nearest enabled one.
446
- if (val && this.isDisabled(type, val)) {
447
- const enabled = this.nearestEnabled(type, origIndex);
448
- if (enabled != null) {
449
- this.scrollToValue(type, list[enabled], true);
450
- origIndex = enabled;
451
- val = list[enabled];
452
- }
453
- } else {
454
- // Enforce a clean rest position (native mandatory-snap usually already did).
455
- const target = index * this.ITEM_HEIGHT;
456
- if (Math.abs(element.scrollTop - target) > 0.5) {
457
- this.scrollToValue(type, val, true);
458
- }
459
- }
460
-
461
- if (!val) return;
462
-
463
- // 4. Commit the selection inside Angular's zone.
464
- if (type === 'hour' && this.selectedHour !== val) {
465
- this.zone.run(() => {
466
- this.selectedHour = val!;
467
- this.computeConstraints();
468
- this.adjustSelectionOnConstraintChange();
469
- });
470
- } else if (type === 'minute' && this.selectedMinute !== val) {
471
- this.zone.run(() => {
472
- this.selectedMinute = val!;
473
- });
474
- } else if (type === 'period' && this.selectedPeriod !== val) {
475
- this.zone.run(() => {
476
- this.selectedPeriod = val!;
477
- this.computeConstraints();
478
- this.adjustSelectionOnConstraintChange();
479
- });
480
- }
481
- }
482
-
483
- // Search outward from origIndex for the closest enabled value index.
484
- private nearestEnabled(type: WheelType, origIndex: number): number | null {
485
- const list = this.listFor(type);
486
- const N = list.length;
487
- const looping = type === 'hour' || type === 'minute';
488
-
489
- if (!this.isDisabled(type, list[origIndex])) return origIndex;
490
-
491
- for (let offset = 1; offset < N; offset++) {
492
- const up = looping ? (origIndex + offset) % N : origIndex + offset;
493
- if (up >= 0 && up < N && !this.isDisabled(type, list[up])) return up;
494
-
495
- const down = looping ? ((origIndex - offset) % N + N) % N : origIndex - offset;
496
- if (down >= 0 && down < N && !this.isDisabled(type, list[down])) return down;
497
- }
498
- return null;
499
- }
500
-
501
- private adjustSelectionOnConstraintChange(): void {
502
- if (this.mode === '12') {
503
- if (this.disabledPeriods.has(this.selectedPeriod)) {
504
- const alt = this.periods.find(p => !this.disabledPeriods.has(p));
505
- if (alt) {
506
- this.selectedPeriod = alt;
507
- this.scrollToValue('period', alt, true);
508
- this.computeConstraints();
509
- }
510
- }
511
-
512
- if (this.disabledHours.has(this.selectedHour)) {
513
- const validHour = this.hours.find(h => !this.disabledHours.has(h));
514
- if (validHour) {
515
- this.selectedHour = validHour;
516
- this.scrollToValue('hour', validHour, true);
517
- this.computeConstraints();
518
- }
519
- }
520
- } else {
521
- if (this.disabledHours.has(this.selectedHour)) {
522
- const validHour = this.hours.find(h => !this.disabledHours.has(h));
523
- if (validHour) {
524
- this.selectedHour = validHour;
525
- this.scrollToValue('hour', validHour, true);
526
- this.computeConstraints();
527
- }
528
- }
529
- }
530
-
531
- if (this.disabledMinutes.has(this.selectedMinute)) {
532
- const validMinute = this.minutes.find(m => !this.disabledMinutes.has(m));
533
- if (validMinute) {
534
- this.selectedMinute = validMinute;
535
- this.scrollToValue('minute', validMinute, true);
536
- }
537
- }
538
- }
539
-
540
- selectValue(type: WheelType, val: string): void {
541
- if (type === 'hour') {
542
- if (this.disabledHours.has(val)) return;
543
- this.selectedHour = val;
544
- } else if (type === 'minute') {
545
- if (this.disabledMinutes.has(val)) return;
546
- this.selectedMinute = val;
547
- } else if (type === 'period') {
548
- if (this.disabledPeriods.has(val)) return;
549
- this.selectedPeriod = val;
550
- }
551
- this.scrollToValue(type, val, true);
552
- this.computeConstraints();
553
- this.adjustSelectionOnConstraintChange();
554
- }
555
-
556
- scrollToValue(type: WheelType, val: string, smooth: boolean): void {
557
- let element: HTMLElement | null = null;
558
- if (type === 'hour') element = this.hourWheel?.nativeElement ?? null;
559
- else if (type === 'minute') element = this.minuteWheel?.nativeElement ?? null;
560
- else element = this.periodWheel?.nativeElement ?? null;
561
-
562
- if (!element) return;
563
-
564
- const list = this.listFor(type);
565
- const index = list.indexOf(val);
566
- if (index === -1) return;
567
-
568
- const looping = type === 'hour' || type === 'minute';
569
- const base = looping ? this.centralBandStart(list, this.repeatsFor(type)) : 0;
570
- const targetIndex = base + index;
571
-
572
- const originalBehavior = element.style.scrollBehavior;
573
- element.style.scrollBehavior = smooth ? 'smooth' : 'auto';
574
- element.scrollTop = targetIndex * this.ITEM_HEIGHT;
575
- // Force layout reflow
576
- const _ = element.scrollTop;
577
- element.style.scrollBehavior = originalBehavior;
578
- }
579
-
580
- onCancel(): void {
581
- this.cancelled.emit();
582
- }
583
-
584
- onConfirm(): void {
585
- this.confirmed.emit(this.getFormattedTime());
586
- }
587
-
588
- getFormattedTime(): string {
589
- if (this.mode === '24') {
590
- return `${this.selectedHour}:${this.selectedMinute}`;
591
- } else {
592
- return `${this.selectedHour}:${this.selectedMinute} ${this.selectedPeriod}`;
593
- }
594
- }
595
- }
@@ -1,49 +0,0 @@
1
- export type TimeMode = '12' | '24';
2
- export type TimePickerVariant = 'default' | 'wheel';
3
-
4
- export interface TimePickerLabels {
5
- label?: string;
6
- placeholder?: string;
7
- hourLabel?: string; // "HOUR" column header — default 'Hour'
8
- minuteLabel?: string; // "MINUTE" column header — default 'Minute'
9
- periodLabel?: string; // "AM/PM" column header — default 'AM/PM'
10
- amLabel?: string; // "AM" — default 'AM'
11
- pmLabel?: string; // "PM" — default 'PM'
12
- confirmLabel?: string; // Confirm button — default 'Confirm'
13
- cancelLabel?: string; // Cancel button — default 'Cancel'
14
- selectTimeTitle?: string; // Popup title — default 'Select Time'
15
- requiredMarker?: string;
16
- clearLabel?: string;
17
- }
18
-
19
- export interface TimePickerConfig {
20
- label?: string;
21
- placeholder?: string;
22
- variant?: TimePickerVariant; // 'default' | 'wheel' — default 'wheel'
23
- mode?: TimeMode; // '12' | '24' — default '12'
24
- minuteStep?: number; // 0/1 (default) = every minute 00–59; 5, 10, 15, 30 add the break
25
- disabled?: boolean;
26
- required?: boolean;
27
- errorMessage?: string;
28
- // Style overrides (mirror datepicker pattern)
29
- width?: string;
30
- height?: string;
31
- borderRadius?: string;
32
- fontSize?: string;
33
- gap?: string;
34
- fontFamily?: string;
35
- labelColor?: string;
36
- labelFontSize?: string;
37
- labelFontWeight?: string;
38
- backgroundColor?: string;
39
- borderColor?: string;
40
- borderWidth?: string;
41
- padding?: string;
42
- fontWeight?: string;
43
- color?: string;
44
- placeholderColor?: string;
45
- focusBorderColor?: string;
46
- errorColor?: string;
47
- disabledBackgroundColor?: string;
48
- disabledColor?: string;
49
- }
@@ -1,23 +0,0 @@
1
- import { NgModule } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { TimePickerComponent } from './components/time-picker/time-picker.component';
5
- import { TimeWheelPanelComponent } from './components/time-wheel-panel/time-wheel-panel.component';
6
- import { FormComponentsModule } from '../form-components/form-components.module';
7
-
8
- @NgModule({
9
- declarations: [
10
- TimePickerComponent,
11
- TimeWheelPanelComponent
12
- ],
13
- imports: [
14
- CommonModule,
15
- FormsModule,
16
- FormComponentsModule
17
- ],
18
- exports: [
19
- TimePickerComponent,
20
- TimeWheelPanelComponent
21
- ]
22
- })
23
- export class TimePickerModule {}