@acpaas-ui/ngx-forms 6.1.9 → 6.1.10

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 (161) hide show
  1. package/.eslintrc.json +42 -0
  2. package/LICENSE.md +21 -0
  3. package/dist/README.md +23 -0
  4. package/dist/esm2020/lib/datepicker/components/datepicker/datepicker.component.mjs +232 -0
  5. package/{fesm2015 → dist/fesm2015}/acpaas-ui-ngx-forms.mjs +7 -4
  6. package/dist/fesm2015/acpaas-ui-ngx-forms.mjs.map +1 -0
  7. package/{fesm2020 → dist/fesm2020}/acpaas-ui-ngx-forms.mjs +7 -4
  8. package/dist/fesm2020/acpaas-ui-ngx-forms.mjs.map +1 -0
  9. package/dist/package.json +44 -0
  10. package/karma.conf.js +38 -0
  11. package/ng-package.json +8 -0
  12. package/package.json +6 -27
  13. package/src/lib/auto-complete/README.md +148 -0
  14. package/src/lib/auto-complete/auto-complete.module.ts +15 -0
  15. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.html +51 -0
  16. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.scss +4 -0
  17. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.spec.ts +378 -0
  18. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.ts +281 -0
  19. package/src/lib/auto-complete/public-api.ts +2 -0
  20. package/src/lib/datepicker/README.md +110 -0
  21. package/src/lib/datepicker/components/datepicker/datepicker.component.html +47 -0
  22. package/src/lib/datepicker/components/datepicker/datepicker.component.scss +13 -0
  23. package/src/lib/datepicker/components/datepicker/datepicker.component.spec.ts +204 -0
  24. package/src/lib/datepicker/components/datepicker/datepicker.component.ts +251 -0
  25. package/src/lib/datepicker/datepicker.conf.ts +11 -0
  26. package/src/lib/datepicker/datepicker.module.ts +50 -0
  27. package/src/lib/datepicker/public-api.ts +8 -0
  28. package/src/lib/datepicker/types/datepicker.types.ts +8 -0
  29. package/src/lib/range-slider/README.md +56 -0
  30. package/src/lib/range-slider/components/range-slider/range-slider.component.html +46 -0
  31. package/src/lib/range-slider/components/range-slider/range-slider.component.scss +12 -0
  32. package/src/lib/range-slider/components/range-slider/range-slider.component.spec.ts +216 -0
  33. package/src/lib/range-slider/components/range-slider/range-slider.component.ts +301 -0
  34. package/src/lib/range-slider/public-api.ts +3 -0
  35. package/src/lib/range-slider/range-slider.module.ts +11 -0
  36. package/src/lib/range-slider/types/range-slider.types.ts +4 -0
  37. package/src/lib/search-filter/README.md +86 -0
  38. package/src/lib/search-filter/components/search-filter/search-filter.component.html +66 -0
  39. package/src/lib/search-filter/components/search-filter/search-filter.component.scss +23 -0
  40. package/src/lib/search-filter/components/search-filter/search-filter.component.spec.ts +264 -0
  41. package/src/lib/search-filter/components/search-filter/search-filter.component.ts +140 -0
  42. package/src/lib/search-filter/public-api.ts +3 -0
  43. package/src/lib/search-filter/search-filter.module.ts +13 -0
  44. package/src/lib/search-filter/types/search-filter.types.ts +4 -0
  45. package/src/lib/shared/services/search.service.spec.ts +78 -0
  46. package/src/lib/shared/services/search.service.ts +32 -0
  47. package/src/lib/shared/types/search.types.ts +6 -0
  48. package/src/lib/timepicker/README.md +84 -0
  49. package/src/lib/timepicker/classes/timepicker.validators.spec.ts +54 -0
  50. package/src/lib/timepicker/classes/timepicker.validators.ts +61 -0
  51. package/src/lib/timepicker/components/timepicker/timepicker.component.html +37 -0
  52. package/src/lib/timepicker/components/timepicker/timepicker.component.scss +3 -0
  53. package/src/lib/timepicker/components/timepicker/timepicker.component.spec.ts +161 -0
  54. package/src/lib/timepicker/components/timepicker/timepicker.component.ts +128 -0
  55. package/src/lib/timepicker/public-api.ts +4 -0
  56. package/src/lib/timepicker/timepicker.module.ts +13 -0
  57. package/src/lib/timepicker/types/timepicker.types.ts +5 -0
  58. package/src/lib/upload/README.md +283 -0
  59. package/src/lib/upload/classes/uploader.class.spec.ts +100 -0
  60. package/src/lib/upload/classes/uploader.class.ts +144 -0
  61. package/src/lib/upload/components/upload/upload.component.html +28 -0
  62. package/src/lib/upload/components/upload/upload.component.scss +3 -0
  63. package/src/lib/upload/components/upload/upload.component.spec.ts +117 -0
  64. package/src/lib/upload/components/upload/upload.component.ts +50 -0
  65. package/src/lib/upload/components/upload-input/upload-input.component.html +11 -0
  66. package/src/lib/upload/components/upload-input/upload-input.component.spec.ts +55 -0
  67. package/src/lib/upload/components/upload-input/upload-input.component.ts +35 -0
  68. package/src/lib/upload/components/upload-queue/upload-queue.component.html +16 -0
  69. package/src/lib/upload/components/upload-queue/upload-queue.component.spec.ts +99 -0
  70. package/src/lib/upload/components/upload-queue/upload-queue.component.ts +36 -0
  71. package/src/lib/upload/components/upload-zone/upload-zone.component.html +55 -0
  72. package/src/lib/upload/components/upload-zone/upload-zone.component.scss +3 -0
  73. package/src/lib/upload/components/upload-zone/upload-zone.component.spec.ts +144 -0
  74. package/src/lib/upload/components/upload-zone/upload-zone.component.ts +142 -0
  75. package/src/lib/upload/components/validation-list/validation-list.component.html +15 -0
  76. package/src/lib/upload/components/validation-list/validation-list.component.spec.ts +57 -0
  77. package/src/lib/upload/components/validation-list/validation-list.component.ts +29 -0
  78. package/src/lib/upload/public-api.ts +10 -0
  79. package/src/lib/upload/services/validation-messages.service.spec.ts +66 -0
  80. package/src/lib/upload/services/validation-messages.service.ts +27 -0
  81. package/src/lib/upload/types/upload.types.ts +20 -0
  82. package/src/lib/upload/upload.conf.ts +15 -0
  83. package/src/lib/upload/upload.module.ts +34 -0
  84. package/src/public-api.ts +6 -0
  85. package/src/test.ts +9 -0
  86. package/tsconfig.lib.json +26 -0
  87. package/tsconfig.spec.json +17 -0
  88. package/esm2020/lib/datepicker/components/datepicker/datepicker.component.mjs +0 -229
  89. package/fesm2015/acpaas-ui-ngx-forms.mjs.map +0 -1
  90. package/fesm2020/acpaas-ui-ngx-forms.mjs.map +0 -1
  91. /package/{esm2020 → dist/esm2020}/acpaas-ui-ngx-forms.mjs +0 -0
  92. /package/{esm2020 → dist/esm2020}/lib/auto-complete/auto-complete.module.mjs +0 -0
  93. /package/{esm2020 → dist/esm2020}/lib/auto-complete/components/auto-complete/auto-complete.component.mjs +0 -0
  94. /package/{esm2020 → dist/esm2020}/lib/auto-complete/public-api.mjs +0 -0
  95. /package/{esm2020 → dist/esm2020}/lib/datepicker/datepicker.conf.mjs +0 -0
  96. /package/{esm2020 → dist/esm2020}/lib/datepicker/datepicker.module.mjs +0 -0
  97. /package/{esm2020 → dist/esm2020}/lib/datepicker/public-api.mjs +0 -0
  98. /package/{esm2020 → dist/esm2020}/lib/datepicker/types/datepicker.types.mjs +0 -0
  99. /package/{esm2020 → dist/esm2020}/lib/range-slider/components/range-slider/range-slider.component.mjs +0 -0
  100. /package/{esm2020 → dist/esm2020}/lib/range-slider/public-api.mjs +0 -0
  101. /package/{esm2020 → dist/esm2020}/lib/range-slider/range-slider.module.mjs +0 -0
  102. /package/{esm2020 → dist/esm2020}/lib/range-slider/types/range-slider.types.mjs +0 -0
  103. /package/{esm2020 → dist/esm2020}/lib/search-filter/components/search-filter/search-filter.component.mjs +0 -0
  104. /package/{esm2020 → dist/esm2020}/lib/search-filter/public-api.mjs +0 -0
  105. /package/{esm2020 → dist/esm2020}/lib/search-filter/search-filter.module.mjs +0 -0
  106. /package/{esm2020 → dist/esm2020}/lib/search-filter/types/search-filter.types.mjs +0 -0
  107. /package/{esm2020 → dist/esm2020}/lib/shared/services/search.service.mjs +0 -0
  108. /package/{esm2020 → dist/esm2020}/lib/shared/types/search.types.mjs +0 -0
  109. /package/{esm2020 → dist/esm2020}/lib/timepicker/classes/timepicker.validators.mjs +0 -0
  110. /package/{esm2020 → dist/esm2020}/lib/timepicker/components/timepicker/timepicker.component.mjs +0 -0
  111. /package/{esm2020 → dist/esm2020}/lib/timepicker/public-api.mjs +0 -0
  112. /package/{esm2020 → dist/esm2020}/lib/timepicker/timepicker.module.mjs +0 -0
  113. /package/{esm2020 → dist/esm2020}/lib/timepicker/types/timepicker.types.mjs +0 -0
  114. /package/{esm2020 → dist/esm2020}/lib/upload/classes/uploader.class.mjs +0 -0
  115. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload/upload.component.mjs +0 -0
  116. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload-input/upload-input.component.mjs +0 -0
  117. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload-queue/upload-queue.component.mjs +0 -0
  118. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload-zone/upload-zone.component.mjs +0 -0
  119. /package/{esm2020 → dist/esm2020}/lib/upload/components/validation-list/validation-list.component.mjs +0 -0
  120. /package/{esm2020 → dist/esm2020}/lib/upload/public-api.mjs +0 -0
  121. /package/{esm2020 → dist/esm2020}/lib/upload/services/validation-messages.service.mjs +0 -0
  122. /package/{esm2020 → dist/esm2020}/lib/upload/types/upload.types.mjs +0 -0
  123. /package/{esm2020 → dist/esm2020}/lib/upload/upload.conf.mjs +0 -0
  124. /package/{esm2020 → dist/esm2020}/lib/upload/upload.module.mjs +0 -0
  125. /package/{esm2020 → dist/esm2020}/public-api.mjs +0 -0
  126. /package/{index.d.ts → dist/index.d.ts} +0 -0
  127. /package/{lib → dist/lib}/auto-complete/auto-complete.module.d.ts +0 -0
  128. /package/{lib → dist/lib}/auto-complete/components/auto-complete/auto-complete.component.d.ts +0 -0
  129. /package/{lib → dist/lib}/auto-complete/public-api.d.ts +0 -0
  130. /package/{lib → dist/lib}/datepicker/components/datepicker/datepicker.component.d.ts +0 -0
  131. /package/{lib → dist/lib}/datepicker/datepicker.conf.d.ts +0 -0
  132. /package/{lib → dist/lib}/datepicker/datepicker.module.d.ts +0 -0
  133. /package/{lib → dist/lib}/datepicker/public-api.d.ts +0 -0
  134. /package/{lib → dist/lib}/datepicker/types/datepicker.types.d.ts +0 -0
  135. /package/{lib → dist/lib}/range-slider/components/range-slider/range-slider.component.d.ts +0 -0
  136. /package/{lib → dist/lib}/range-slider/public-api.d.ts +0 -0
  137. /package/{lib → dist/lib}/range-slider/range-slider.module.d.ts +0 -0
  138. /package/{lib → dist/lib}/range-slider/types/range-slider.types.d.ts +0 -0
  139. /package/{lib → dist/lib}/search-filter/components/search-filter/search-filter.component.d.ts +0 -0
  140. /package/{lib → dist/lib}/search-filter/public-api.d.ts +0 -0
  141. /package/{lib → dist/lib}/search-filter/search-filter.module.d.ts +0 -0
  142. /package/{lib → dist/lib}/search-filter/types/search-filter.types.d.ts +0 -0
  143. /package/{lib → dist/lib}/shared/services/search.service.d.ts +0 -0
  144. /package/{lib → dist/lib}/shared/types/search.types.d.ts +0 -0
  145. /package/{lib → dist/lib}/timepicker/classes/timepicker.validators.d.ts +0 -0
  146. /package/{lib → dist/lib}/timepicker/components/timepicker/timepicker.component.d.ts +0 -0
  147. /package/{lib → dist/lib}/timepicker/public-api.d.ts +0 -0
  148. /package/{lib → dist/lib}/timepicker/timepicker.module.d.ts +0 -0
  149. /package/{lib → dist/lib}/timepicker/types/timepicker.types.d.ts +0 -0
  150. /package/{lib → dist/lib}/upload/classes/uploader.class.d.ts +0 -0
  151. /package/{lib → dist/lib}/upload/components/upload/upload.component.d.ts +0 -0
  152. /package/{lib → dist/lib}/upload/components/upload-input/upload-input.component.d.ts +0 -0
  153. /package/{lib → dist/lib}/upload/components/upload-queue/upload-queue.component.d.ts +0 -0
  154. /package/{lib → dist/lib}/upload/components/upload-zone/upload-zone.component.d.ts +0 -0
  155. /package/{lib → dist/lib}/upload/components/validation-list/validation-list.component.d.ts +0 -0
  156. /package/{lib → dist/lib}/upload/public-api.d.ts +0 -0
  157. /package/{lib → dist/lib}/upload/services/validation-messages.service.d.ts +0 -0
  158. /package/{lib → dist/lib}/upload/types/upload.types.d.ts +0 -0
  159. /package/{lib → dist/lib}/upload/upload.conf.d.ts +0 -0
  160. /package/{lib → dist/lib}/upload/upload.module.d.ts +0 -0
  161. /package/{public-api.d.ts → dist/public-api.d.ts} +0 -0
@@ -0,0 +1,251 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ ChangeDetectorRef,
4
+ Component,
5
+ EventEmitter,
6
+ forwardRef,
7
+ Inject,
8
+ Input,
9
+ OnChanges,
10
+ OnDestroy,
11
+ OnInit,
12
+ Output,
13
+ SimpleChanges,
14
+ ViewChild,
15
+ } from '@angular/core';
16
+ import { Subject } from 'rxjs';
17
+ import { takeUntil } from 'rxjs/operators';
18
+ import {
19
+ ControlValueAccessor,
20
+ UntypedFormBuilder,
21
+ UntypedFormControl,
22
+ NG_VALIDATORS,
23
+ NG_VALUE_ACCESSOR,
24
+ } from '@angular/forms';
25
+ import { DateHelper, DateRange } from '@acpaas-ui/ngx-utils';
26
+ import { TZDate } from '@date-fns/tz';
27
+ import { FlyoutDirective } from '@acpaas-ui/ngx-flyout';
28
+ import {
29
+ CALENDAR_DEFAULT_MONTH_LABELS,
30
+ CALENDAR_DEFAULT_WEEKDAY_LABELS,
31
+ CALENDAR_MONTH_LABELS,
32
+ CALENDAR_WEEKDAY_LABELS,
33
+ CalendarService,
34
+ DatepickerResult,
35
+ WeekdayLabelsConfig,
36
+ MonthLabelsConfig,
37
+ } from '@acpaas-ui/ngx-calendar';
38
+
39
+ import {
40
+ DATEPICKER_SEPARATOR_CHAR,
41
+ DATEPICKER_DEFAULT_ERROR_LABELS,
42
+ DATEPICKER_ERROR_LABELS,
43
+ } from '../../datepicker.conf';
44
+ import { DatepickerValidationErrors } from '../../types/datepicker.types';
45
+ import { Interval, IntervalBuilder } from '@acpaas-ui/ngx-utils';
46
+
47
+ @Component({
48
+ selector: 'aui-datepicker',
49
+ templateUrl: './datepicker.component.html',
50
+ styleUrls: ['./datepicker.component.scss'],
51
+ changeDetection: ChangeDetectionStrategy.OnPush,
52
+ providers: [
53
+ {
54
+ provide: NG_VALUE_ACCESSOR,
55
+ useExisting: forwardRef(() => DatepickerComponent), // eslint-disable-line @angular-eslint/no-forward-ref
56
+ multi: true,
57
+ },
58
+ {
59
+ provide: NG_VALIDATORS,
60
+ useExisting: forwardRef(() => DatepickerComponent), // eslint-disable-line @angular-eslint/no-forward-ref
61
+ multi: true,
62
+ },
63
+ ],
64
+ })
65
+ export class DatepickerComponent implements OnInit, OnChanges, OnDestroy, ControlValueAccessor {
66
+ @ViewChild(FlyoutDirective, { static: true }) flyout: FlyoutDirective;
67
+ @Input() id: string;
68
+ @Input() name: string;
69
+ @Input() placeholder = 'dd/mm/yyyy';
70
+ @Input() label: string;
71
+ @Input() description: string;
72
+ @Input() range: DateRange;
73
+ @Input()
74
+ min: Date | null;
75
+ @Input()
76
+ max: Date | null;
77
+ @Input() autocomplete: 'off';
78
+ @Input() weekdayLabels: WeekdayLabelsConfig;
79
+ @Input() monthLabels: MonthLabelsConfig;
80
+ @Input() ariaOpenDatepickerLabel = 'Open kalender';
81
+
82
+ // eslint-disable-next-line @angular-eslint/no-output-native
83
+ @Output() blur = new EventEmitter<Event>();
84
+
85
+ public formControl: UntypedFormControl;
86
+ public selectedDate: Date;
87
+ public isDisabled = false;
88
+ public interval: Interval.IInterval<Date>;
89
+
90
+ private componentDestroyed$: Subject<boolean> = new Subject<boolean>();
91
+
92
+ constructor(
93
+ @Inject(CALENDAR_MONTH_LABELS) private moduleMonthLabels = CALENDAR_DEFAULT_MONTH_LABELS,
94
+ @Inject(CALENDAR_WEEKDAY_LABELS) private moduleWeekdayLabels = CALENDAR_DEFAULT_WEEKDAY_LABELS,
95
+ @Inject(DATEPICKER_ERROR_LABELS) private errorLabels = DATEPICKER_DEFAULT_ERROR_LABELS,
96
+ public calendarService: CalendarService,
97
+ private formBuilder: UntypedFormBuilder,
98
+ private ref: ChangeDetectorRef
99
+ ) {}
100
+
101
+ public ngOnInit(): void {
102
+ this.weekdayLabels = this.weekdayLabels || this.moduleWeekdayLabels;
103
+ this.monthLabels = this.monthLabels || this.moduleMonthLabels;
104
+ this.createInterval();
105
+ this.formControl = this.formBuilder.control({ value: '', disabled: this.isDisabled });
106
+ this.formControl.valueChanges.pipe(takeUntil(this.componentDestroyed$)).subscribe((value) => {
107
+ if (value) {
108
+ const date = DateHelper.parseDate(value, 'dd/MM/yyyy');
109
+ if (date instanceof Date) {
110
+ this.selectedDate = date;
111
+ const brusselsDate = new TZDate(date, 'Europe/Brussels');
112
+ const year = brusselsDate.getFullYear();
113
+ const month = brusselsDate.getMonth();
114
+ const day = brusselsDate.getDate();
115
+ this.onChange(DateHelper.toUtcMidnightInBrussels(year, month, day));
116
+ } else if (typeof date === 'string') {
117
+ this.onChange(value);
118
+ } else {
119
+ this.onChange(value);
120
+ }
121
+ } else {
122
+ this.selectedDate = null;
123
+ this.onChange('');
124
+ }
125
+ });
126
+ }
127
+
128
+ public ngOnChanges(changes: SimpleChanges): void {
129
+ if (changes.min || changes.max) {
130
+ this.createInterval();
131
+ }
132
+ }
133
+
134
+ public ngOnDestroy(): void {
135
+ this.componentDestroyed$.next(true);
136
+ this.componentDestroyed$.complete();
137
+ }
138
+
139
+ private createInterval() {
140
+ if (!this.min && !this.max) {
141
+ return;
142
+ }
143
+ // Create an interval if min/max is filled in
144
+ this.interval = IntervalBuilder.dateInterval(
145
+ this.min ? new Date(this.min) : null,
146
+ this.max ? new Date(this.max) : null
147
+ )
148
+ .not()
149
+ .build();
150
+ }
151
+
152
+ public writeValue(value: string | Date): void {
153
+ if (typeof value === 'string') {
154
+ if (this.isISODateFormat(value)) {
155
+ this.selectedDate = DateHelper.parseDate(value) as Date;
156
+ } else {
157
+ const parsed = DateHelper.parseDate(value, 'dd/MM/yyyy');
158
+ this.selectedDate = parsed instanceof Date ? parsed : null;
159
+ }
160
+ } else if (value instanceof Date) {
161
+ this.selectedDate = value;
162
+ } else {
163
+ this.selectedDate = null;
164
+ }
165
+
166
+ const dateString = this.selectedDate ? this.formatDate(this.selectedDate) : '';
167
+ this.formControl.setValue(dateString);
168
+ }
169
+
170
+ public registerOnChange(onChange: (res: any) => void): void {
171
+ this.onChange = onChange;
172
+ }
173
+
174
+ public registerOnTouched(onTouched: (_: any) => void): void {
175
+ this.onTouched = onTouched;
176
+ }
177
+
178
+ public setDisabledState(isDisabled: boolean): void {
179
+ this.isDisabled = isDisabled;
180
+
181
+ if (this.formControl) {
182
+ if (isDisabled && this.formControl.enabled) {
183
+ this.formControl.disable();
184
+ } else if (!isDisabled && this.formControl.disabled) {
185
+ this.formControl.enable();
186
+ }
187
+ }
188
+
189
+ this.ref.markForCheck();
190
+ }
191
+
192
+ public selectDateFromCalendar(result: DatepickerResult): void {
193
+ if (result.complete) {
194
+ this.formControl.setValue(this.formatDate(result.date));
195
+ this.flyout.close();
196
+ }
197
+ }
198
+
199
+ public formatDate(date: Date): string {
200
+ return DateHelper.formatDate(date, 'DD/MM/YYYY', {
201
+ leadingZero: true,
202
+ monthLabels: this.monthLabels,
203
+ weekdayLabels: this.weekdayLabels,
204
+ });
205
+ }
206
+
207
+ public validate(ctrl: UntypedFormControl): DatepickerValidationErrors {
208
+ // no error on empty value (add required validator in app)
209
+ if (ctrl.value === '' || ctrl.value === null) {
210
+ return null;
211
+ }
212
+
213
+ // throw format error if no valid date was provided
214
+ const date = DateHelper.parseDate(ctrl.value);
215
+ if (!date) {
216
+ return {
217
+ format: this.errorLabels.ERRORS_INVALID_DATE,
218
+ };
219
+ }
220
+
221
+ // no error if valid date an no range provided
222
+ if (!this.range || !this.range.length) {
223
+ return null;
224
+ }
225
+
226
+ // throw error when out of range
227
+ const range = this.calendarService.getRangeForDate(date, this.range);
228
+
229
+ return range.indexOf(date.getDate()) >= 0
230
+ ? {
231
+ range: this.errorLabels.ERRORS_INVALID_RANGE,
232
+ }
233
+ : null;
234
+ }
235
+
236
+ public handleBlur(e: Event): void {
237
+ this.blur.emit(e);
238
+ this.onTouched(e);
239
+ }
240
+
241
+ private onChange: (res: any) => void = () => undefined;
242
+
243
+ private onTouched: (_: any) => void = () => undefined;
244
+
245
+ private isISODateFormat(value: string) {
246
+ if (typeof value !== 'string') {
247
+ return false;
248
+ }
249
+ return value.match(/\d{4}-\d{2}-\d{2}T.*/);
250
+ }
251
+ }
@@ -0,0 +1,11 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { DatepickerErrorLabels } from './types/datepicker.types';
3
+
4
+ export const DATEPICKER_ERROR_LABELS = new InjectionToken<DatepickerErrorLabels>('errorLabels');
5
+
6
+ export const DATEPICKER_DEFAULT_ERROR_LABELS = {
7
+ ERRORS_INVALID_DATE: 'INVALID_DATE',
8
+ ERRORS_INVALID_RANGE: 'INVALID_RANGE',
9
+ };
10
+
11
+ export const DATEPICKER_SEPARATOR_CHAR = '/';
@@ -0,0 +1,50 @@
1
+ import { ModuleWithProviders, NgModule } from '@angular/core';
2
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
3
+ import { CommonModule } from '@angular/common';
4
+
5
+ import { FlyoutModule } from '@acpaas-ui/ngx-flyout';
6
+ import {
7
+ CALENDAR_DEFAULT_MONTH_LABELS,
8
+ CALENDAR_DEFAULT_WEEKDAY_LABELS,
9
+ CALENDAR_MONTH_LABELS,
10
+ CALENDAR_WEEKDAY_LABELS,
11
+ CalendarModule,
12
+ } from '@acpaas-ui/ngx-calendar';
13
+ import { IconModule } from '@acpaas-ui/ngx-icon';
14
+
15
+ import { DatepickerComponent } from './components/datepicker/datepicker.component';
16
+ import { DATEPICKER_DEFAULT_ERROR_LABELS, DATEPICKER_ERROR_LABELS } from './datepicker.conf';
17
+ import { DatepickerErrorLabels } from './types/datepicker.types';
18
+
19
+ @NgModule({
20
+ imports: [CommonModule, FormsModule, ReactiveFormsModule, CalendarModule, IconModule, FlyoutModule],
21
+ declarations: [DatepickerComponent],
22
+ exports: [DatepickerComponent],
23
+ providers: [
24
+ {
25
+ provide: CALENDAR_WEEKDAY_LABELS,
26
+ useValue: CALENDAR_DEFAULT_WEEKDAY_LABELS,
27
+ },
28
+ { provide: CALENDAR_MONTH_LABELS, useValue: CALENDAR_DEFAULT_MONTH_LABELS },
29
+ {
30
+ provide: DATEPICKER_ERROR_LABELS,
31
+ useValue: DATEPICKER_DEFAULT_ERROR_LABELS,
32
+ },
33
+ ],
34
+ })
35
+ export class DatepickerModule {
36
+ static forChild(
37
+ weekdayLabels: string[],
38
+ monthLabels: string[],
39
+ errorLabels: DatepickerErrorLabels
40
+ ): ModuleWithProviders<DatepickerModule> {
41
+ return {
42
+ ngModule: DatepickerModule,
43
+ providers: [
44
+ { provide: CALENDAR_WEEKDAY_LABELS, useValue: weekdayLabels },
45
+ { provide: CALENDAR_MONTH_LABELS, useValue: monthLabels },
46
+ { provide: DATEPICKER_ERROR_LABELS, useValue: errorLabels },
47
+ ],
48
+ };
49
+ }
50
+ }
@@ -0,0 +1,8 @@
1
+ export { DatepickerComponent } from './components/datepicker/datepicker.component';
2
+ export { DatepickerErrorLabels, DatepickerValidationErrors } from './types/datepicker.types';
3
+ export {
4
+ DATEPICKER_DEFAULT_ERROR_LABELS,
5
+ DATEPICKER_ERROR_LABELS,
6
+ DATEPICKER_SEPARATOR_CHAR,
7
+ } from './datepicker.conf';
8
+ export { DatepickerModule } from './datepicker.module';
@@ -0,0 +1,8 @@
1
+ export interface DatepickerValidationErrors {
2
+ [key: string]: any;
3
+ }
4
+
5
+ export interface DatepickerErrorLabels {
6
+ ERRORS_INVALID_DATE?: string;
7
+ ERRORS_INVALID_RANGE?: string;
8
+ }
@@ -0,0 +1,56 @@
1
+ # @acpaas-ui/ngx-forms
2
+
3
+ Use the range slider as stand alone component or in a form.
4
+
5
+ ## Usage
6
+
7
+ ```typescript
8
+ import { RangeSliderModule } from '@acpaas-ui/ngx-forms';
9
+ ```
10
+
11
+ ## Documentation
12
+
13
+ Visit our [documentation site](https://antwerp-ui.digipolis.be/) for full how-to docs and guidelines
14
+
15
+ ### API
16
+
17
+ | Name | Default value | Description |
18
+ | ----------------------------------- | ------------- | ------------------------------------------------------ |
19
+ | `@Input() min: number;` | `0` | Minimum value on the slider. |
20
+ | `@Input() max: number;` | `100` | Maximum value on the slider. |
21
+ | `@Input() minimalDistance: number;` | `1` | The minimum interval between the start and end values. |
22
+ | `@Input() step: number;` | `0` | The numeric steps shown on the slider. |
23
+ | `@Input() labelBefore: string;` | `''` | Label before the text on the slider. |
24
+ | `@Input() labelAfter: string;` | `''` | Label before the text on the slider. |
25
+
26
+ ### Example
27
+
28
+ ```typescript
29
+ import { RangeSliderModule } from '@acpaas-ui/ngx-forms';
30
+
31
+ @NgModule({
32
+ imports: [
33
+ RangeSliderModule,
34
+ ]
35
+ });
36
+
37
+ export class AppModule {};
38
+ ```
39
+
40
+ ```typescript
41
+ public mySlider = {start: 400, end: 500};
42
+ ```
43
+
44
+ ```html
45
+ <div class="example">
46
+ <aui-range-slider></aui-range-slider>
47
+
48
+ <aui-range-slider step="20" labelAfter="%"> </aui-range-slider>
49
+
50
+ <aui-range-slider [(ngModel)]="mySlider" min="300" max="600" labelBefore="€"> </aui-range-slider>
51
+ </div>
52
+ ```
53
+
54
+ ## Contributing
55
+
56
+ Visit our [Contribution Guidelines](../../../../../CONTRIBUTING.md) for more information on how to contribute.
@@ -0,0 +1,46 @@
1
+ <div class="a-range-slider">
2
+ <div class="a-range-slider__labels">
3
+ <div class="a-range-slider__label">{{ label }}</div>
4
+ </div>
5
+ <div class="a-range-slider__inner">
6
+ <div class="a-range-slider__tickmarks">
7
+ <div *ngFor="let step of steps; let i = index" class="a-range-slider__tickmark"></div>
8
+ </div>
9
+ <div
10
+ [style.left]="endPercentage ? startPercentage + '%' : false"
11
+ [style.width]="endPercentage ? endPercentage - startPercentage + '%' : startPercentage + '%'"
12
+ class="a-range-slider__bar"
13
+ ></div>
14
+ <span
15
+ (blur)="toggleFocus(false, null, $event)"
16
+ (dragexit)="onMouseUp($event)"
17
+ (focus)="toggleFocus(true, 'start', $event)"
18
+ (mousedown)="onMouseDown('start')"
19
+ (touchstart)="onMouseDown('start')"
20
+ [style.left]="startPercentage + '%'"
21
+ class="a-range-slider__handle"
22
+ [attr.aria-label]="ariaLabelMin"
23
+ tabindex="0"
24
+ >
25
+ </span>
26
+
27
+ <span
28
+ (blur)="toggleFocus(false, null, $event)"
29
+ (dragexit)="onMouseUp($event)"
30
+ (focus)="toggleFocus(true, 'end', $event)"
31
+ (mousedown)="onMouseDown('end')"
32
+ (touchstart)="onMouseDown('end')"
33
+ *ngIf="end"
34
+ [style.left]="endPercentage + '%'"
35
+ class="a-range-slider__handle"
36
+ name="a-range-slider__handle__end"
37
+ [attr.aria-label]="ariaLabelMax"
38
+ tabindex="0"
39
+ >
40
+ </span>
41
+ </div>
42
+ <div class="a-range-slider__descriptions">
43
+ <div class="a-range-slider__description small">{{ labelBefore }}{{ min }}{{ labelAfter }}</div>
44
+ <div class="a-range-slider__description small">{{ labelBefore }}{{ max }}{{ labelAfter }}</div>
45
+ </div>
46
+ </div>
@@ -0,0 +1,12 @@
1
+ :host {
2
+ display: block;
3
+ position: relative;
4
+
5
+ &.is-disabled {
6
+ cursor: not-allowed;
7
+
8
+ .m-range-slider__handle:hover {
9
+ cursor: not-allowed;
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,216 @@
1
+ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { DebugElement } from '@angular/core';
3
+
4
+ import { RangeSliderComponent } from './range-slider.component';
5
+
6
+ describe('The RangeSlider Component', () => {
7
+ let comp: RangeSliderComponent;
8
+ let fixture: ComponentFixture<RangeSliderComponent>;
9
+ let de: DebugElement;
10
+ let el: HTMLElement;
11
+
12
+ // waitForAsync beforeEach
13
+ beforeEach(waitForAsync(() => {
14
+ TestBed.configureTestingModule({
15
+ declarations: [RangeSliderComponent], // declare the test component
16
+ }).compileComponents(); // compile template and css
17
+ }));
18
+
19
+ // synchronous beforeEach
20
+ beforeEach(() => {
21
+ fixture = TestBed.createComponent(RangeSliderComponent);
22
+
23
+ comp = fixture.componentInstance; // BannerComponent test instance
24
+
25
+ // query for the title <h1> by CSS element selector
26
+ de = fixture.debugElement;
27
+ el = de.nativeElement;
28
+ });
29
+
30
+ it('should exist', () => {
31
+ fixture.detectChanges();
32
+ expect(el).not.toBeUndefined();
33
+ });
34
+
35
+ it('should write values', () => {
36
+ spyOn(comp, 'setStart').and.callThrough();
37
+ comp.writeValue('');
38
+ expect(comp.setStart).toHaveBeenCalledWith(0);
39
+ expect(comp.startPercentage).toEqual(0);
40
+
41
+ comp.min = 10;
42
+ comp.max = 50;
43
+ fixture.detectChanges();
44
+ comp.writeValue('');
45
+ expect(comp.setStart).toHaveBeenCalledWith(10);
46
+ expect(comp.startPercentage).toEqual(0);
47
+
48
+ comp.writeValue(30);
49
+ expect(comp.start).toEqual(30);
50
+ expect(comp.startPercentage).toEqual(50);
51
+
52
+ comp.writeValue({ start: 20 });
53
+ expect(comp.start).toEqual(20);
54
+ expect(comp.startPercentage).toEqual(25);
55
+
56
+ comp.writeValue({ start: 20, end: 50 });
57
+ expect(comp.start).toEqual(20);
58
+ expect(comp.startPercentage).toEqual(25);
59
+ expect(comp.end).toEqual(50);
60
+ expect(comp.endPercentage).toEqual(100);
61
+ });
62
+
63
+ it('should round on mouse up', () => {
64
+ spyOn(comp, 'setStart');
65
+ comp.active = 'start';
66
+ comp.click = true;
67
+ fixture.detectChanges();
68
+
69
+ comp.onMouseUp({});
70
+ expect(comp.setStart).toHaveBeenCalled();
71
+ spyOn(comp, 'setEnd');
72
+ comp.active = 'end';
73
+ fixture.detectChanges();
74
+
75
+ comp.onMouseUp({});
76
+ expect(comp.setEnd).toHaveBeenCalled();
77
+ });
78
+
79
+ it('should not call updateHandle on mouse move if there is no active handle', () => {
80
+ spyOn(comp, 'updateHandle');
81
+ comp.onMouseMove({
82
+ x: 0,
83
+ preventDefault: () => {
84
+ return;
85
+ },
86
+ } as any);
87
+ expect(comp.updateHandle).not.toHaveBeenCalled();
88
+ });
89
+
90
+ it('should call updateHandle on mouse move if there is an active handle', () => {
91
+ spyOn(comp, 'updateHandle');
92
+ comp.active = 'target';
93
+ comp.click = true;
94
+ comp.onMouseMove({
95
+ x: 0,
96
+ preventDefault: () => {
97
+ return;
98
+ },
99
+ } as any);
100
+ expect(comp.updateHandle).toHaveBeenCalled();
101
+ });
102
+
103
+ it('should calculate new percentage', () => {
104
+ expect(comp.calcPercentage(10, 100, 0)).toEqual(10);
105
+ expect(comp.calcPercentage(20, 100, 10)).toEqual(10);
106
+ expect(comp.calcPercentage(10, 100, 30)).toEqual(0);
107
+ expect(comp.calcPercentage(140, 100, 30)).toEqual(100);
108
+ expect(comp.calcPercentage(130, 100, 30)).toEqual(100);
109
+ });
110
+
111
+ it('schould activate handle on mouse down', () => {
112
+ comp.onMouseDown('start');
113
+ expect(comp.active).toEqual('start');
114
+ });
115
+
116
+ it('should round numbers', () => {
117
+ expect(comp.round(47, 20, 0)).toBe(40);
118
+ expect(comp.round(47, 20, 10)).toBe(50);
119
+ expect(comp.round(47, 0, 0)).toBe(47);
120
+
121
+ expect(comp.round(45, 10, 0)).toBe(50);
122
+ expect(comp.round(46, 10, 0)).toBe(50);
123
+ expect(comp.round(44, 10, 0)).toBe(40);
124
+ });
125
+
126
+ it('should calculate startPercentage to start', () => {
127
+ fixture.detectChanges();
128
+
129
+ comp.startPercentage = 50;
130
+ comp.min = 10;
131
+ comp.max = 50;
132
+ fixture.detectChanges();
133
+
134
+ expect(comp.percentageToStart()).toBe(30);
135
+ });
136
+
137
+ describe('Example with defined start', () => {
138
+ it('should calculate startPercentage', () => {
139
+ comp.start = 10;
140
+ comp.min = 10;
141
+ comp.max = 50;
142
+ fixture.detectChanges();
143
+
144
+ expect(comp.startPercentage).toBe(0);
145
+
146
+ comp.start = 30;
147
+ fixture.detectChanges();
148
+ expect(comp.startToPercentage()).toBe(50);
149
+ });
150
+ });
151
+
152
+ describe('Example with defined end', () => {
153
+ it('should calculate startPercentage', () => {
154
+ comp.end = 40;
155
+ comp.min = 10;
156
+ comp.max = 50;
157
+ fixture.detectChanges();
158
+
159
+ expect(comp.endPercentage).toBe(75);
160
+
161
+ comp.end = 30;
162
+ fixture.detectChanges();
163
+ expect(comp.endToPercentage()).toBe(50);
164
+ });
165
+
166
+ it('should keep minimal distance', () => {
167
+ comp.start = 20;
168
+ comp.end = 80;
169
+ comp.min = 0;
170
+ comp.max = 100;
171
+ comp.minimalDistance = 20;
172
+ comp.active = 'end';
173
+ fixture.detectChanges();
174
+
175
+ comp.updateHandle(30);
176
+ expect(comp.start).toBe(20);
177
+ expect(comp.startPercentage).toBe(20);
178
+ expect(comp.end).toBe(40);
179
+ expect(comp.endPercentage).toBe(40);
180
+
181
+ comp.updateHandle(50);
182
+ expect(comp.start).toBe(20);
183
+ expect(comp.startPercentage).toBe(20);
184
+ expect(comp.end).toBe(50);
185
+ expect(comp.endPercentage).toBe(50);
186
+
187
+ comp.active = 'start';
188
+ fixture.detectChanges();
189
+
190
+ comp.updateHandle(45);
191
+ expect(comp.start).toBe(30);
192
+ expect(comp.startPercentage).toBe(30);
193
+ expect(comp.end).toBe(50);
194
+ expect(comp.endPercentage).toBe(50);
195
+
196
+ comp.updateHandle(10);
197
+ expect(comp.start).toBe(10);
198
+ expect(comp.startPercentage).toBe(10);
199
+ expect(comp.end).toBe(50);
200
+ expect(comp.endPercentage).toBe(50);
201
+ });
202
+ });
203
+
204
+ describe('Example with steps', () => {
205
+ beforeEach(() => {
206
+ comp.min = 10;
207
+ comp.max = 50;
208
+ comp.step = 10;
209
+ fixture.detectChanges();
210
+ });
211
+
212
+ it('should calculate steps', () => {
213
+ expect(comp.steps).toEqual([0, 10, 20, 30, 40, 50]);
214
+ });
215
+ });
216
+ });