@klippa/ngx-enhancy-forms 4.0.0 → 5.0.0

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 (39) hide show
  1. package/bundles/klippa-ngx-enhancy-forms.umd.js +547 -90
  2. package/bundles/klippa-ngx-enhancy-forms.umd.js.map +1 -1
  3. package/bundles/klippa-ngx-enhancy-forms.umd.min.js +2 -2
  4. package/bundles/klippa-ngx-enhancy-forms.umd.min.js.map +1 -1
  5. package/esm2015/lib/elements/date-picker/date-picker.component.js +92 -0
  6. package/esm2015/lib/elements/date-time-picker/date-time-picker.component.js +311 -0
  7. package/esm2015/lib/elements/email/email-input.component.js +2 -2
  8. package/esm2015/lib/elements/password-field/password-field.component.js +6 -4
  9. package/esm2015/lib/elements/select/select-footer/select-footer.component.js +15 -0
  10. package/esm2015/lib/elements/select/select.component.js +30 -9
  11. package/esm2015/lib/elements/sortable-items/sortable-items.component.js +46 -4
  12. package/esm2015/lib/elements/text-input/text-input.component.js +7 -4
  13. package/esm2015/lib/elements/value-accessor-base/multiple-value-accessor-base.component.js +63 -0
  14. package/esm2015/lib/elements/value-accessor-base/value-accessor-base.component.js +3 -3
  15. package/esm2015/lib/form/form-element/form-element.component.js +13 -15
  16. package/esm2015/lib/form/form.component.js +21 -5
  17. package/esm2015/lib/ngx-enhancy-forms.module.js +13 -4
  18. package/esm2015/lib/util/values.js +8 -17
  19. package/esm2015/public-api.js +5 -2
  20. package/fesm2015/klippa-ngx-enhancy-forms.js +512 -78
  21. package/fesm2015/klippa-ngx-enhancy-forms.js.map +1 -1
  22. package/klippa-ngx-enhancy-forms.metadata.json +1 -1
  23. package/lib/elements/date-picker/date-picker.component.d.ts +23 -0
  24. package/lib/elements/date-time-picker/date-time-picker.component.d.ts +59 -0
  25. package/lib/elements/email/email-input.component.d.ts +1 -1
  26. package/lib/elements/password-field/password-field.component.d.ts +2 -1
  27. package/lib/elements/select/select-footer/select-footer.component.d.ts +4 -0
  28. package/lib/elements/select/select.component.d.ts +12 -4
  29. package/lib/elements/sortable-items/sortable-items.component.d.ts +12 -2
  30. package/lib/elements/text-input/text-input.component.d.ts +2 -0
  31. package/lib/elements/value-accessor-base/multiple-value-accessor-base.component.d.ts +11 -0
  32. package/lib/elements/value-accessor-base/value-accessor-base.component.d.ts +2 -1
  33. package/lib/form/form-element/form-element.component.d.ts +5 -5
  34. package/lib/form/form.component.d.ts +2 -0
  35. package/lib/util/values.d.ts +2 -4
  36. package/package.json +1 -1
  37. package/public-api.d.ts +4 -1
  38. package/esm2015/lib/elements/datepicker/datepicker.component.js +0 -111
  39. package/lib/elements/datepicker/datepicker.component.d.ts +0 -26
@@ -1,16 +1,17 @@
1
- import { Directive, Input, Component, SkipSelf, Optional, InjectionToken, Host, Inject, ViewChild, HostBinding, EventEmitter, Output, ContentChild, TemplateRef, NgModule } from '@angular/core';
1
+ import { Directive, Input, Component, SkipSelf, Optional, InjectionToken, Host, Inject, ViewChild, HostBinding, EventEmitter, Output, ContentChild, TemplateRef, ChangeDetectorRef, NgModule } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormArray, FormGroup, FormControl, ControlContainer, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
4
4
  import { isString } from 'lodash';
5
5
  import { SortablejsModule } from 'ngx-sortablejs';
6
6
  import { NgSelectModule } from '@ng-select/ng-select';
7
+ import { parse, format, startOfMonth, endOfMonth } from 'date-fns';
7
8
  import { MAT_NATIVE_DATE_FORMATS, MAT_DATE_FORMATS, MatNativeDateModule } from '@angular/material/core';
8
9
  import { MatDatepickerModule } from '@angular/material/datepicker';
9
10
  import { MatFormFieldModule } from '@angular/material/form-field';
10
11
  import { MatInputModule } from '@angular/material/input';
11
12
  import { MatButtonModule } from '@angular/material/button';
12
13
 
13
- function stringIsSetAndNotEmpty(s) {
14
+ function stringIsSetAndFilled(s) {
14
15
  return isString(s) && s.length > 0;
15
16
  }
16
17
  function isNullOrUndefined(value) {
@@ -22,24 +23,15 @@ function numberIsSet(value) {
22
23
  function isValueSet(value) {
23
24
  return value !== null && value !== undefined;
24
25
  }
26
+ function removeDuplicatesFromArray(array) {
27
+ return array.filter((c, i) => {
28
+ const firstOccurrenceIndex = array.findIndex((c2) => c2 === c);
29
+ return i === firstOccurrenceIndex;
30
+ });
31
+ }
25
32
  function stringOrArrayIsSetAndEmpty(value) {
26
33
  return value !== null && value !== undefined && value.length === 0;
27
34
  }
28
- function useIfStringIsSet(s) {
29
- if (stringIsSetAndNotEmpty(s)) {
30
- return s;
31
- }
32
- return undefined;
33
- }
34
- function useIfArrayIsSetWithOneItem(a) {
35
- if (!isNullOrUndefined(a) && a.length === 1) {
36
- return a[0];
37
- }
38
- return undefined;
39
- }
40
- function convertParentToChild(originalClass, newClass) {
41
- return Object.assign(newClass, originalClass);
42
- }
43
35
  function truncateString(s, length) {
44
36
  if (s.length < length) {
45
37
  return s;
@@ -72,18 +64,21 @@ class FormComponent {
72
64
  const injectInto = this.subFormPlaceholder.injectInto;
73
65
  const injectAt = this.subFormPlaceholder.at;
74
66
  if (injectInto instanceof FormArray) {
75
- if (typeof injectAt !== "number") {
67
+ if (typeof injectAt !== 'number') {
76
68
  throw new Error(`cannot index FormArray with ${typeof injectAt}`);
77
69
  }
78
70
  injectInto.setControl(injectAt, this.formGroup);
79
71
  }
80
72
  else if (injectInto instanceof FormGroup) {
81
- if (typeof injectAt !== "string") {
73
+ if (typeof injectAt !== 'string') {
82
74
  throw new Error(`cannot index FormGroup with ${typeof injectAt}`);
83
75
  }
84
76
  injectInto.setControl(injectAt, this.formGroup);
85
77
  }
86
78
  }
79
+ if (isValueSet(this.patchValueInterceptor)) {
80
+ this.addSupportForPatchValueInterceptor();
81
+ }
87
82
  }
88
83
  ngOnDestroy() {
89
84
  if (isValueSet(this.parent) && isValueSet(this.subFormPlaceholder)) {
@@ -94,13 +89,24 @@ class FormComponent {
94
89
  injectInto.removeAt(idx);
95
90
  }
96
91
  else if (injectInto instanceof FormGroup) {
97
- if (typeof injectAt !== "string") {
92
+ if (typeof injectAt !== 'string') {
98
93
  throw new Error(`cannot index FormGroup with ${typeof injectAt}`);
99
94
  }
100
95
  injectInto.removeControl(injectAt);
101
96
  }
102
97
  }
103
98
  }
99
+ addSupportForPatchValueInterceptor() {
100
+ const fn = this.formGroup.patchValue;
101
+ const newFn = (value, options) => {
102
+ this.patchValueInterceptor(value).then((val) => {
103
+ setTimeout(() => {
104
+ fn.call(this.formGroup, val, options);
105
+ });
106
+ });
107
+ };
108
+ this.formGroup.patchValue = newFn;
109
+ }
104
110
  registerControl(formControl, formElement) {
105
111
  this.activeControls.push({ formControl, formElement });
106
112
  if (this.parent) {
@@ -154,6 +160,7 @@ class FormComponent {
154
160
  }
155
161
  trySubmit() {
156
162
  var _a, _b;
163
+ this.formGroup.updateValueAndValidity();
157
164
  this.formGroup.markAllAsTouched();
158
165
  const allControls = this.getAllFormControls();
159
166
  const originalDisabledStates = allControls.map(e => {
@@ -194,20 +201,21 @@ FormComponent.ctorParameters = () => [
194
201
  { type: SubFormDirective, decorators: [{ type: Optional }] }
195
202
  ];
196
203
  FormComponent.propDecorators = {
197
- formGroup: [{ type: Input }]
204
+ formGroup: [{ type: Input }],
205
+ patchValueInterceptor: [{ type: Input }]
198
206
  };
199
207
 
200
208
  const FORM_ERROR_MESSAGES = new InjectionToken('form.error.messages');
201
209
  const DEFAULT_ERROR_MESSAGES = {
202
- min: "Use a number larger than %min%",
203
- max: "Use a number smaller than %max%",
204
- required: "This field is required",
205
- email: "Use a valid email address",
206
- minLength: "Has to be longer than %minLength% character(s)",
207
- maxLength: "Has to be shorter than %maxLength% character(s)",
208
- pattern: "This input is not valid",
209
- matchPassword: "Passwords must match",
210
- date: "Enter a valid date",
210
+ min: 'Use a number larger than %min%',
211
+ max: 'Use a number smaller than %max%',
212
+ required: 'This field is required',
213
+ email: 'Use a valid email address',
214
+ minLength: 'Has to be longer than %minLength% character(s)',
215
+ maxLength: 'Has to be shorter than %maxLength% character(s)',
216
+ pattern: 'This input is not valid',
217
+ matchPassword: 'Passwords must match',
218
+ date: 'Enter a valid date',
211
219
  };
212
220
  class FormElementComponent {
213
221
  constructor(parent, customMessages) {
@@ -225,8 +233,6 @@ class FormElementComponent {
225
233
  }, message);
226
234
  }
227
235
  registerControl(formControl) {
228
- // console.log('register');
229
- // console.log(this.caption);
230
236
  this.attachedControl = formControl;
231
237
  this.parent.registerControl(formControl, this);
232
238
  }
@@ -273,7 +279,7 @@ class FormElementComponent {
273
279
  // to give some breathing room, we scroll 100px more to the top
274
280
  (_a = this.getScrollableParent(this.internalComponentRef.nativeElement)) === null || _a === void 0 ? void 0 : _a.scrollBy(0, -100);
275
281
  }
276
- getErrorMessages(key) {
282
+ getErrorMessage(key) {
277
283
  var _a, _b, _c;
278
284
  return (_c = (_b = (_a = this.customMessages) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : this.errorMessages[key];
279
285
  }
@@ -281,7 +287,7 @@ class FormElementComponent {
281
287
  FormElementComponent.decorators = [
282
288
  { type: Component, args: [{
283
289
  selector: 'klp-form-element',
284
- template: "<ng-template #errorRef>\n\t<div *ngIf=\"getErrorToShow()\" class=\"errorContainer\">\n\t\t<div *ngIf=\"showDefaultError('min')\">{{substituteParameters(getErrorMessages(\"min\"), {min: attachedControl.errors.min.min})}}</div>\n\t\t<div *ngIf=\"showDefaultError('max')\">{{substituteParameters(getErrorMessages(\"max\"), {max: attachedControl.errors.max.max})}}</div>\n\t\t<div *ngIf=\"showDefaultError('required')\">{{getErrorMessages(\"required\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('email')\">{{getErrorMessages(\"email\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('minlength')\">{{substituteParameters(getErrorMessages(\"minLength\"), {minLength: attachedControl.errors.minlength.requiredLength})}}</div>\n\t\t<div *ngIf=\"showDefaultError('maxlength')\">{{substituteParameters(getErrorMessages(\"maxLength\"), {maxLength: attachedControl.errors.maxlength.requiredLength})}}</div>\n\t\t<div *ngIf=\"showDefaultError('pattern')\">{{getErrorMessages(\"pattern\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('MatchPassword')\">{{getErrorMessages(\"matchPassword\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('date')\">{{getErrorMessages(\"date\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('message')\">{{attachedControl.errors.message.value}}</div>\n\t\t<div [ngTemplateOutlet]=\"getCustomErrorHandler(getErrorToShow())?.templateRef\"></div>\n\t</div>\n</ng-template>\n<ng-container *ngIf=\"direction === 'horizontal'\" [ngTemplateOutlet]=\"errorRef\"></ng-container>\n<div *ngIf=\"attachedControl\" class=\"componentContainer\" [ngClass]=\"{vertical: direction === 'vertical', reverseOrder: swapInputAndCaption}\" #internalComponentRef>\n\t<div class=\"caption\" [ngClass]=\"{ hasErrors: getErrorToShow() && attachedControl.touched, percentageSpacing: captionSpacing === 'percentages' }\">\n\t\t<div *ngIf=\"captionRef\" [ngTemplateOutlet]=\"captionRef\"></div>\n\t\t<div *ngIf=\"!captionRef\">{{caption}}</div>\n\t</div>\n\t<ng-container *ngIf=\"direction === 'vertical'\" [ngTemplateOutlet]=\"errorRef\"></ng-container>\n\t<div class=\"inputContainer\" [ngClass]=\"{ percentageSpacing: captionSpacing === 'percentages' }\">\n\t\t<ng-content></ng-content>\n\t</div>\n</div>\n",
290
+ template: "<ng-template #errorRef>\n\t<div *ngIf=\"getErrorToShow()\" class=\"errorContainer\">\n\t\t<div *ngIf=\"showDefaultError('min')\">{{substituteParameters(getErrorMessage(\"min\"), {min: attachedControl.errors.min.min})}}</div>\n\t\t<div *ngIf=\"showDefaultError('max')\">{{substituteParameters(getErrorMessage(\"max\"), {max: attachedControl.errors.max.max})}}</div>\n\t\t<div *ngIf=\"showDefaultError('required')\">{{getErrorMessage(\"required\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('email')\">{{getErrorMessage(\"email\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('minlength')\">{{substituteParameters(getErrorMessage(\"minLength\"), {minLength: attachedControl.errors.minlength.requiredLength})}}</div>\n\t\t<div *ngIf=\"showDefaultError('maxlength')\">{{substituteParameters(getErrorMessage(\"maxLength\"), {maxLength: attachedControl.errors.maxlength.requiredLength})}}</div>\n\t\t<div *ngIf=\"showDefaultError('pattern')\">{{getErrorMessage(\"pattern\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('MatchPassword')\">{{getErrorMessage(\"matchPassword\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('date')\">{{getErrorMessage(\"date\")}}</div>\n\t\t<div *ngIf=\"showDefaultError('message')\">{{attachedControl.errors.message.value}}</div>\n\t\t<div [ngTemplateOutlet]=\"getCustomErrorHandler(getErrorToShow())?.templateRef\"></div>\n\t</div>\n</ng-template>\n<ng-container *ngIf=\"direction === 'horizontal'\" [ngTemplateOutlet]=\"errorRef\"></ng-container>\n<div *ngIf=\"attachedControl\" class=\"componentContainer\" [ngClass]=\"{vertical: direction === 'vertical', reverseOrder: swapInputAndCaption}\" #internalComponentRef>\n\t<div class=\"caption\" [ngClass]=\"{ hasErrors: getErrorToShow() && attachedControl.touched, percentageSpacing: captionSpacing === 'percentages' }\">\n\t\t<div *ngIf=\"captionRef\" [ngTemplateOutlet]=\"captionRef\"></div>\n\t\t<div *ngIf=\"!captionRef\">{{caption}}</div>\n\t</div>\n\t<ng-container *ngIf=\"direction === 'vertical'\" [ngTemplateOutlet]=\"errorRef\"></ng-container>\n\t<div class=\"inputContainer\" [ngClass]=\"{ percentageSpacing: captionSpacing === 'percentages' }\">\n\t\t<ng-content></ng-content>\n\t</div>\n</div>\n",
285
291
  styles: [":host{display:block;margin-top:1.25rem}.componentContainer{align-items:center;display:flex}.componentContainer.reverseOrder{flex-direction:row-reverse;justify-content:flex-end}.componentContainer.vertical{display:block;margin-bottom:1rem}.componentContainer.vertical .inputContainer{margin-top:.3125rem}.componentContainer.vertical .errorContainer{margin-left:0}.caption{color:#515365;flex:0 0 auto;font-weight:700}.caption.percentageSpacing{flex:0 0 40%}.caption.hasErrors{color:#ff8000}.inputContainer{flex:0 0 auto}.inputContainer.percentageSpacing{flex:0 0 60%}.errorContainer{color:#ff8000;margin-left:40%}"]
286
292
  },] }
287
293
  ];
@@ -322,7 +328,7 @@ class ValueAccessorBase {
322
328
  if (this.formControl) {
323
329
  this.attachedFormControl = this.formControl;
324
330
  }
325
- else if (stringIsSetAndNotEmpty(this.formControlName)) {
331
+ else if (stringIsSetAndFilled(this.formControlName)) {
326
332
  this.attachedFormControl = (_a = this.controlContainer) === null || _a === void 0 ? void 0 : _a.control.get(this.formControlName);
327
333
  if (isNullOrUndefined(this.attachedFormControl)) {
328
334
  throw new Error(`Form element '${this.formControlName}' with caption '${(_b = this.parent) === null || _b === void 0 ? void 0 : _b.caption}' is not declared in your FormGroup.`);
@@ -487,92 +493,173 @@ class PasswordFieldComponent extends ValueAccessorBase {
487
493
  constructor() {
488
494
  super(...arguments);
489
495
  this.placeholder = 'Password';
496
+ this.isPasswordConfirm = false;
490
497
  }
491
498
  }
492
499
  PasswordFieldComponent.decorators = [
493
500
  { type: Component, args: [{
494
501
  selector: 'klp-form-password-field',
495
- template: "<input\n\ttype=\"password\"\n\tclass=\"form-control\"\n [ngClass]=\"{showErrors: isInErrorState()}\"\n\t[(ngModel)]=\"innerValue\"\n\t(input)=\"setInnerValueAndNotify($event.target.value)\"\n\t[placeholder]=\"placeholder\"\n\t(blur)=\"touch()\"\n/>\n",
502
+ template: "<input\n\ttype=\"password\"\n\tclass=\"form-control\"\n [ngClass]=\"{showErrors: isInErrorState()}\"\n\t[(ngModel)]=\"innerValue\"\n\t(input)=\"setInnerValueAndNotify($event.target.value)\"\n\t[placeholder]=\"isPasswordConfirm ? 'Confirm password': 'Password'\"\n\t(blur)=\"touch()\"\n/>\n",
496
503
  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: PasswordFieldComponent, multi: true }],
497
504
  styles: [":host,input{display:block}input{-moz-transition:all .2s ease-in;-ms-transition:all .2s ease-in;-o-transition:all .2s ease-in;-webkit-transition:all .2s ease-in;border:1px solid #e6ecf5;border-radius:2px;box-shadow:none;color:#888da8;font-size:14px;height:42px;outline:none;padding:.375rem .625rem;transition:all .2s ease-in;width:100%}input::-webkit-input-placeholder{color:#adadad}input:-moz-placeholder,input::-moz-placeholder{color:#adadad}input:-ms-input-placeholder{color:#adadad}input:focus{border-color:#3ed778;box-shadow:none;outline:0 none}input.input-sm{height:30px}input.input-lg{height:50px}input.error{background-color:#ffeff4;border-color:#ff3c7e}input.valid{background-color:#ebfaeb;border-color:#37c936;color:#278d26}.showErrors{border-color:#ff8000}"]
498
505
  },] }
499
506
  ];
500
507
  PasswordFieldComponent.propDecorators = {
501
- placeholder: [{ type: Input }]
508
+ placeholder: [{ type: Input }],
509
+ isPasswordConfirm: [{ type: Input }]
502
510
  };
503
511
 
512
+ const SELECT_TRANSLATIONS = new InjectionToken('klp.form.select.translations');
504
513
  class SelectComponent extends ValueAccessorBase {
505
- constructor(parent, controlContainer) {
514
+ constructor(parent, controlContainer, translations) {
506
515
  super(parent, controlContainer);
507
516
  this.parent = parent;
508
517
  this.controlContainer = controlContainer;
509
- this.placeholder = 'Pick an option';
518
+ this.translations = translations;
510
519
  this.multiple = false;
520
+ this.multipleDisplayedAsAmount = false;
511
521
  this.clearable = true;
512
522
  this.onSearch = new EventEmitter();
513
523
  }
524
+ onTextInput(value) {
525
+ this.currentQueryString = value;
526
+ this.onSearch.emit(value);
527
+ }
528
+ getDefaultTranslation(key) {
529
+ switch (key) {
530
+ case 'placeholder':
531
+ return () => { var _a; return (_a = this.placeholder) !== null && _a !== void 0 ? _a : 'Pick an option'; };
532
+ case 'amountSelected':
533
+ return (amount) => `${amount} selected`;
534
+ }
535
+ }
536
+ getTranslation(key, params = null) {
537
+ var _a, _b, _c;
538
+ return (_c = (_b = (_a = this.translations) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.call(_a, params)) !== null && _c !== void 0 ? _c : this.getDefaultTranslation(key)(params);
539
+ }
514
540
  }
515
541
  SelectComponent.decorators = [
516
542
  { type: Component, args: [{
517
543
  selector: 'klp-form-select',
518
- template: "<ng-select\n\t[placeholder]=\"placeholder\"\n\tbindLabel=\"name\"\n\tbindValue=\"id\"\n\t[items]=\"options\"\n\t[clearable]=\"clearable\"\n\t[(ngModel)]=\"innerValue\"\n\t[ngClass]=\"{showErrors: isInErrorState()}\"\n\t(change)=\"setInnerValueAndNotify(innerValue)\"\n\t[multiple]=\"multiple\"\n\t[disabled]=\"disabled\"\n\t(blur)=\"touch()\"\n\t(search)=\"onSearch.emit($event.term)\"\n\t[dropdownPosition]=\"dropdownPosition\"\n\t[searchFn]=\"customSearchFn\"\n>\n\t<ng-template let-item=\"item\" ng-option-tmp>\n\t\t{{ item.name }}\n\t\t<div *ngIf=\"item.description\" class=\"dropdown-item-description\">\n\t\t\t{{ item.description }}\n\t\t</div>\n\t</ng-template>\n</ng-select>\n",
544
+ template: "<ng-select\n\t[placeholder]=\"getTranslation('placeholder')\"\n\tbindLabel=\"name\"\n\tbindValue=\"id\"\n\t[items]=\"options\"\n\t[clearable]=\"clearable\"\n\t[(ngModel)]=\"innerValue\"\n\t[ngClass]=\"{showErrors: isInErrorState()}\"\n\t(change)=\"setInnerValueAndNotify(innerValue)\"\n\t[multiple]=\"multiple\"\n\t[disabled]=\"disabled\"\n\t(blur)=\"touch()\"\n\t(search)=\"onSearch.emit($event.term)\"\n\t[dropdownPosition]=\"dropdownPosition\"\n\t[searchFn]=\"customSearchFn\"\n\t(input)=\"onTextInput($event.target.value)\"\n>\n\t<ng-template let-item=\"item\" ng-option-tmp>\n\t\t{{ item.name }}\n\t\t<div *ngIf=\"item.description\" class=\"dropdown-item-description\">\n\t\t\t{{ item.description }}\n\t\t</div>\n\t</ng-template>\n\t<ng-container *ngIf=\"multiple && multipleDisplayedAsAmount && innerValue?.length > 1\">\n\t\t<ng-template ng-multi-label-tmp>\n\t\t\t<div class=\"ng-value\">\n\t\t\t\t<span class=\"ng-value-label\">{{getTranslation('amountSelected', innerValue?.length)}}</span>\n\t\t\t</div>\n\t\t</ng-template>\n\t</ng-container>\n\t<ng-template ng-footer-tmp *ngIf=\"footerElement\">\n\t\t<ng-container [ngTemplateOutlet]=\"footerElement\"></ng-container>\n\t</ng-template>\n</ng-select>\n",
519
545
  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: SelectComponent, multi: true }],
520
- styles: [":host{display:block}.showErrors ::ng-deep .ng-select-container,:host.showErrors ::ng-deep .ng-select-container{border-color:#ff8000}:host ::ng-deep ng-select.ng-select .ng-select-container{color:#888da8}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container{background:#fff;border-color:#3ed778}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container:hover{box-shadow:none}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container .ng-arrow{border-color:transparent transparent #999;border-width:0 5px 5px;top:-2px}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container .ng-arrow:hover{border-color:transparent transparent #666}:host ::ng-deep .ng-select.ng-select-opened.ng-select-bottom>.ng-select-container{border-bottom-left-radius:0;border-bottom-right-radius:0}:host ::ng-deep .ng-select.ng-select-opened.ng-select-top>.ng-select-container{border-top-left-radius:0;border-top-right-radius:0}:host ::ng-deep .ng-select.ng-select-disabled>.ng-select-container{background-color:#f9f9f9}:host ::ng-deep .ng-select .ng-has-value .ng-placeholder{display:none}:host ::ng-deep .ng-select .ng-select-container{align-items:center;background-clip:padding-box;background-color:#fff;border:1px solid #e6ecf5;border-radius:4px;border-radius:2px;box-shadow:none;box-sizing:border-box;color:#888da8;display:flex;flex-direction:row;font-size:1rem;font-size:14px;line-height:1.5;margin:0;min-height:42px;outline:none;overflow:visible;padding:.375rem .75rem;transition-delay:0s;transition-duration:.2s;transition-property:all;transition-timing-function:ease-in;width:100%}:host ::ng-deep .ng-select .ng-select-container:hover{box-shadow:0 1px 0 rgba(0,0,0,.06)}:host ::ng-deep .ng-select .ng-select-container .ng-value-container{align-items:center;overflow:hidden;padding-left:10px}:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-placeholder{color:#aaa}:host ::ng-deep .ng-select.ng-select-single .ng-select-container{height:42px}:host ::ng-deep .ng-select.ng-select-single .ng-select-container .ng-value-container .ng-input{left:0;padding-left:10px;padding-right:50px;top:5px}:host ::ng-deep .ng-select.ng-select-multiple.ng-select-disabled>.ng-select-container .ng-value-container .ng-value{background-color:#f9f9f9;border:1px solid #e3e3e3}:host ::ng-deep .ng-select.ng-select-multiple.ng-select-disabled>.ng-select-container .ng-value-container .ng-value .ng-value-label{padding:0 5px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container{padding-left:7px;padding-right:10px;padding-top:2px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value{background-color:#e7faee;border:1px solid #93e8b3;border-radius:2px;display:flex;font-size:.9em;margin-bottom:5px;margin-right:5px;overflow:hidden}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value.ng-value-disabled{background-color:#f9f9f9;border:1px solid #e3e3e3}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value.ng-value-disabled .ng-value-label{padding-left:5px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-label{display:inline-block;overflow:hidden;padding:0 5px;text-overflow:ellipsis}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon{display:inline-block;padding:0 5px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon:hover{background-color:#93e8b3}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon.left{border-right:1px solid #93e8b3}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon.right{border-left:1px solid #c2e0ff}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-input{padding-bottom:3px;padding-left:3px}:host ::ng-deep ng-select.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder{padding-bottom:3px;padding-left:3px;position:static;top:5px}:host ::ng-deep .ng-select .ng-clear-wrapper{color:#999}:host ::ng-deep .ng-select .ng-clear-wrapper .ng-clear:hover{color:#ff3c7e}:host ::ng-deep .ng-select .ng-spinner-zone{padding-right:5px;padding-top:5px}:host ::ng-deep .ng-select .ng-arrow-wrapper{padding-right:5px;width:25px}:host ::ng-deep .ng-select .ng-arrow-wrapper:hover .ng-arrow{border-top-color:#666}:host ::ng-deep .ng-select .ng-arrow-wrapper .ng-arrow{border-color:#999 transparent transparent;border-style:solid;border-width:5px 5px 2.5px}:host ::ng-deep .ng-dropdown-panel{background-color:#fff;border:1px solid #3ed778;box-shadow:0 1px 0 rgba(0,0,0,.06)}:host ::ng-deep .ng-dropdown-panel.ng-select-bottom{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-top-color:#e6e6e6;margin-top:-1px;top:100%}:host ::ng-deep .ng-dropdown-panel.ng-select-bottom .ng-dropdown-panel-items .ng-option:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px}:host ::ng-deep .ng-dropdown-panel.ng-select-top{border-bottom-color:#e6e6e6;border-top-left-radius:4px;border-top-right-radius:4px;bottom:100%;margin-bottom:-1px}:host ::ng-deep .ng-dropdown-panel.ng-select-top .ng-dropdown-panel-items .ng-option:first-child{border-top-left-radius:4px;border-top-right-radius:4px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-header{border-bottom:1px solid #ccc;padding:5px 7px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-footer{border-top:1px solid #ccc;padding:5px 7px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items{margin-bottom:1px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;color:rgba(0,0,0,.54);cursor:default;cursor:pointer;font-weight:500;padding:8px 10px;user-select:none}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup.ng-option-disabled{cursor:default}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup.ng-option-marked{background-color:#ebf5ff}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup.ng-option-selected{background-color:#f5faff;font-weight:600}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option{background-color:#fff;color:rgba(0,0,0,.87);padding:8px 10px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected{background-color:#e7faee;color:#333}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected .ng-option-label{font-weight:600}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked{background-color:#e7faee;color:#333}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-disabled{color:#ccc}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-child{padding-left:22px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option .ng-tag-label{font-size:80%;font-weight:400;padding-right:5px}:host ::ng-deep ng-select.ng-select .ng-select-container .ng-value-container{padding-left:0}:host ::ng-deep ng-select.ng-select.ng-select-single .ng-select-container .ng-value-container .ng-input{color:#888da8;top:9px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option,:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input{color:#888da8}:host ::ng-deep .ng-select.ng-select-auto-grow{max-width:inherit}:host ::ng-deep .ng-select.ng-select-auto-grow .ng-dropdown-panel{width:auto}"]
546
+ styles: [":host{display:block}.showErrors ::ng-deep .ng-select-container,:host.showErrors ::ng-deep .ng-select-container{border-color:#ff8000}:host ::ng-deep ng-select.ng-select .ng-select-container{color:#888da8}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container{background:#fff;border-color:#3ed778}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container:hover{box-shadow:none}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container .ng-arrow{border-color:transparent transparent #999;border-width:0 5px 5px;top:-2px}:host ::ng-deep .ng-select.ng-select-opened>.ng-select-container .ng-arrow:hover{border-color:transparent transparent #666}:host ::ng-deep .ng-select.ng-select-opened.ng-select-bottom>.ng-select-container{border-bottom-left-radius:0;border-bottom-right-radius:0}:host ::ng-deep .ng-select.ng-select-opened.ng-select-top>.ng-select-container{border-top-left-radius:0;border-top-right-radius:0}:host ::ng-deep .ng-select.ng-select-disabled>.ng-select-container{background-color:#f9f9f9}:host ::ng-deep .ng-select .ng-has-value .ng-placeholder{display:none}:host ::ng-deep .ng-select .ng-select-container{align-items:center;background-clip:padding-box;background-color:#fff;border:1px solid #e6ecf5;border-radius:4px;border-radius:2px;box-shadow:none;box-sizing:border-box;color:#888da8;display:flex;flex-direction:row;font-size:1rem;font-size:14px;line-height:1.5;margin:0;min-height:42px;outline:none;overflow:visible;padding:.375rem .75rem;transition-delay:0s;transition-duration:.2s;transition-property:all;transition-timing-function:ease-in;width:100%}:host ::ng-deep .ng-select .ng-select-container:hover{box-shadow:0 1px 0 rgba(0,0,0,.06)}:host ::ng-deep .ng-select .ng-select-container .ng-value-container{align-items:center;overflow:hidden;padding-left:10px}:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-placeholder{color:#aaa}:host ::ng-deep .ng-select.ng-select-single .ng-select-container{height:42px}:host ::ng-deep .ng-select.ng-select-single .ng-select-container .ng-value-container .ng-input{left:0;padding-left:10px;padding-right:50px;top:5px}:host ::ng-deep .ng-select.ng-select-multiple.ng-select-disabled>.ng-select-container .ng-value-container .ng-value{background-color:#f9f9f9;border:1px solid #e3e3e3}:host ::ng-deep .ng-select.ng-select-multiple.ng-select-disabled>.ng-select-container .ng-value-container .ng-value .ng-value-label{padding:0 5px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value{background-color:#e7faee;border:1px solid #93e8b3;border-radius:2px;display:flex;font-size:.9em;margin-bottom:3px;margin-right:5px;margin-top:3px;overflow:hidden}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value.ng-value-disabled{background-color:#f9f9f9;border:1px solid #e3e3e3}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value.ng-value-disabled .ng-value-label{padding-left:5px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-label{display:inline-block;overflow:hidden;padding:0 5px;text-overflow:ellipsis}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon{display:inline-block;padding:0 5px}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon:hover{background-color:#93e8b3}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon.left{border-right:1px solid #93e8b3}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value .ng-value-icon.right{border-left:1px solid #c2e0ff}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-input{padding-bottom:3px;padding-left:3px}:host ::ng-deep ng-select.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder{padding-bottom:3px;padding-left:3px;position:static;top:5px}:host ::ng-deep .ng-select .ng-clear-wrapper{color:#999}:host ::ng-deep .ng-select .ng-clear-wrapper .ng-clear:hover{color:#ff3c7e}:host ::ng-deep .ng-select .ng-spinner-zone{padding-right:5px;padding-top:5px}:host ::ng-deep .ng-select .ng-arrow-wrapper{padding-right:5px;width:25px}:host ::ng-deep .ng-select .ng-arrow-wrapper:hover .ng-arrow{border-top-color:#666}:host ::ng-deep .ng-select .ng-arrow-wrapper .ng-arrow{border-color:#999 transparent transparent;border-style:solid;border-width:5px 5px 2.5px}:host ::ng-deep .ng-dropdown-panel{background-color:#fff;border:1px solid #3ed778;box-shadow:0 1px 0 rgba(0,0,0,.06)}:host ::ng-deep .ng-dropdown-panel.ng-select-bottom{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-top-color:#e6e6e6;margin-top:-1px;top:100%}:host ::ng-deep .ng-dropdown-panel.ng-select-bottom .ng-dropdown-panel-items .ng-option:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px}:host ::ng-deep .ng-dropdown-panel.ng-select-top{border-bottom-color:#e6e6e6;border-top-left-radius:4px;border-top-right-radius:4px;bottom:100%;margin-bottom:-1px}:host ::ng-deep .ng-dropdown-panel.ng-select-top .ng-dropdown-panel-items .ng-option:first-child{border-top-left-radius:4px;border-top-right-radius:4px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-header{border-bottom:1px solid #ccc;padding:5px 7px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-footer{border-top:1px solid #ccc;padding:5px 7px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items{margin-bottom:1px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;color:rgba(0,0,0,.54);cursor:default;cursor:pointer;font-weight:500;padding:8px 10px;user-select:none}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup.ng-option-disabled{cursor:default}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup.ng-option-marked{background-color:#ebf5ff}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-optgroup.ng-option-selected{background-color:#f5faff;font-weight:600}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option{background-color:#fff;color:rgba(0,0,0,.87);padding:8px 10px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected{background-color:#e7faee;color:#333}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected .ng-option-label{font-weight:600}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked{background-color:#e7faee;color:#333}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-disabled{color:#ccc}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-child{padding-left:22px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option .ng-tag-label{font-size:80%;font-weight:400;padding-right:5px}:host ::ng-deep ng-select.ng-select .ng-select-container .ng-value-container{padding-left:0}:host ::ng-deep ng-select.ng-select.ng-select-single .ng-select-container .ng-value-container .ng-input{color:#888da8;top:9px}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option,:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input{color:#888da8}:host ::ng-deep .ng-select.ng-select-auto-grow{max-width:inherit}:host ::ng-deep .ng-select.ng-select-auto-grow .ng-dropdown-panel{width:auto}"]
521
547
  },] }
522
548
  ];
523
549
  SelectComponent.ctorParameters = () => [
524
550
  { type: FormElementComponent, decorators: [{ type: Optional }, { type: Host }] },
525
- { type: ControlContainer, decorators: [{ type: Optional }, { type: Host }] }
551
+ { type: ControlContainer, decorators: [{ type: Optional }, { type: Host }] },
552
+ { type: undefined, decorators: [{ type: Inject, args: [SELECT_TRANSLATIONS,] }, { type: Optional }] }
526
553
  ];
527
554
  SelectComponent.propDecorators = {
528
555
  placeholder: [{ type: Input }],
529
556
  options: [{ type: Input }],
530
557
  multiple: [{ type: Input }],
558
+ multipleDisplayedAsAmount: [{ type: Input }],
531
559
  clearable: [{ type: Input }],
532
560
  dropdownPosition: [{ type: Input }],
533
561
  customSearchFn: [{ type: Input }],
562
+ footerElement: [{ type: Input }],
534
563
  onSearch: [{ type: Output }]
535
564
  };
536
565
 
566
+ class SelectFooterComponent {
567
+ }
568
+ SelectFooterComponent.decorators = [
569
+ { type: Component, args: [{
570
+ selector: 'klp-select-footer',
571
+ template: "<div class=\"componentContainer\">\n\t<span class=\"prefix\">{{prefix}}</span>\n\t<span class=\"text\">{{text}}</span>\n</div>\n",
572
+ styles: [":host{display:block}.componentContainer{cursor:pointer;padding:6px 10px}.componentContainer:hover{background:#e7faee}.prefix{font-size:80%;padding-right:.625rem}"]
573
+ },] }
574
+ ];
575
+ SelectFooterComponent.propDecorators = {
576
+ prefix: [{ type: Input }],
577
+ text: [{ type: Input }]
578
+ };
579
+
537
580
  class SortableItemsComponent extends ValueAccessorBase {
538
581
  constructor() {
539
582
  super(...arguments);
540
583
  this.sortableItemSize = 'lg';
584
+ this.useCustomScroll = false;
585
+ this.scrollInterval = null;
541
586
  this.itemsOrderChanged = () => {
542
587
  this.setInnerValueAndNotify(this.innerValue);
543
588
  };
589
+ this.onItemDrag = (data) => {
590
+ // if the item you're dragging is reaching the top, start scrolling.
591
+ if (data.relatedRect.top < 100) {
592
+ this.scrollPage(100);
593
+ }
594
+ else {
595
+ this.stopScrolling();
596
+ }
597
+ };
598
+ this.onEnd = () => {
599
+ this.stopScrolling();
600
+ };
601
+ }
602
+ ngOnInit() {
603
+ super.ngOnInit();
604
+ if (this.useCustomScroll) {
605
+ this.sortablejsOptions = { onUpdate: this.itemsOrderChanged, onMove: this.onItemDrag, onEnd: this.onEnd };
606
+ }
607
+ else {
608
+ this.sortablejsOptions = { onUpdate: this.itemsOrderChanged };
609
+ }
610
+ }
611
+ scrollPage(scrollAmount) {
612
+ if (!isValueSet(this.scrollInterval)) {
613
+ this.scrollInterval = setInterval(() => {
614
+ window.scroll({
615
+ top: document.scrollingElement.scrollTop - scrollAmount,
616
+ behavior: 'smooth',
617
+ });
618
+ if (document.scrollingElement.scrollTop <= 100) {
619
+ this.stopScrolling();
620
+ }
621
+ }, 100);
622
+ }
623
+ }
624
+ stopScrolling() {
625
+ clearInterval(this.scrollInterval);
626
+ this.scrollInterval = null;
544
627
  }
545
628
  }
546
629
  SortableItemsComponent.decorators = [
547
630
  { type: Component, args: [{
548
631
  selector: 'klp-form-sortable-items',
549
- template: "<ng-template #listItem>\n\t<li *ngFor=\"let item of innerValue; index as index\"\n\t class=\"sortableItem\"\n\t [ngClass]=\"{\n\t\t\tlargeSortableItem: sortableItemSize === 'lg',\n\t\t \tsmallSortableItem: sortableItemSize === 'sm'\n\t\t }\"\n\t>\n\t\t<ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"{ item: item, index:index }\" ></ng-container>\n\t</li>\n</ng-template>\n\n<ol *ngIf='!disabled'\n [sortablejs]=\"innerValue\"\n [sortablejsOptions]=\"{ onUpdate: itemsOrderChanged }\"\n class=\"itemsContainer\"\n>\n\t<ng-container *ngTemplateOutlet=\"listItem\"></ng-container>\n</ol>\n\n<ol *ngIf='disabled' class=\"itemsContainer disabled-mouse-cursor\">\n\t<ng-container *ngTemplateOutlet=\"listItem\"></ng-container>\n</ol>\n",
632
+ template: "<ng-template #listItem>\n\t<li *ngFor=\"let item of innerValue; index as index\"\n\t\t\tclass=\"sortableItem\"\n\t\t\t[ngClass]=\"{\n\t\t\tlargeSortableItem: sortableItemSize === 'lg',\n\t\t \tsmallSortableItem: sortableItemSize === 'sm'\n\t\t }\"\n\t>\n\t\t<ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"{ item: item, index:index }\"></ng-container>\n\t</li>\n</ng-template>\n\n<ol *ngIf='!disabled'\n\t\t[sortablejs]=\"innerValue\"\n\t\t[sortablejsOptions]=\"sortablejsOptions\"\n\t\tclass=\"itemsContainer\"\n>\n\t<ng-container *ngTemplateOutlet=\"listItem\"></ng-container>\n</ol>\n\n<ol *ngIf='disabled' class=\"itemsContainer disabled-mouse-cursor\">\n\t<ng-container *ngTemplateOutlet=\"listItem\"></ng-container>\n</ol>\n",
550
633
  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: SortableItemsComponent, multi: true }],
551
634
  styles: [":host{display:block}.itemsContainer{border:1px solid #e6ecf5;border-radius:5px;margin-bottom:0;padding:0}.sortableItem{border-top:1px solid #e6ecf5;cursor:-webkit-grab;cursor:grab;list-style:none}.sortableItem:hover{background:#f8f9fa}.sortableItem:first-child{border-top:none}.largeSortableItem{padding:15px}.smallSortableItem{padding:0 10px}.disabled-mouse-cursor li{cursor:no-drop}"]
552
635
  },] }
553
636
  ];
554
637
  SortableItemsComponent.propDecorators = {
555
638
  template: [{ type: ContentChild, args: [TemplateRef,] }],
556
- sortableItemSize: [{ type: Input }]
639
+ sortableItemSize: [{ type: Input }],
640
+ useCustomScroll: [{ type: Input }]
557
641
  };
558
642
 
559
643
  class TextInputComponent extends ValueAccessorBase {
560
644
  constructor() {
561
645
  super(...arguments);
562
646
  this.type = 'text';
647
+ this.clearable = false;
563
648
  }
564
649
  }
565
650
  TextInputComponent.decorators = [
566
651
  { type: Component, args: [{
567
652
  selector: 'klp-form-text-input',
568
- template: "<input\n\t[type]=\"type\"\n\tclass=\"form-control\"\n\t[ngClass]=\"{showErrors: isInErrorState()}\"\n\t[(ngModel)]=\"innerValue\"\n\t(input)=\"setInnerValueAndNotify($event.target.value)\"\n\t[placeholder]=\"placeholder ? placeholder : ''\"\n\t(blur)=\"touch()\"\n\t[disabled]='disabled'\n/>\n",
653
+ template: "<div class=\"componentContainer\">\n\t<ng-container *ngIf=\"icon?.length > 0\">\n\t\t<i class=\"ti-search\" *ngIf=\"icon === 'search'\"></i>\n\t</ng-container>\n\t<input\n\t\t[type]=\"type\"\n\t\t[ngClass]=\"{showErrors: isInErrorState(), hasIcon: icon?.length > 0, hasClearButton: clearable}\"\n\t\t[(ngModel)]=\"innerValue\"\n\t\t(input)=\"setInnerValueAndNotify($event.target.value)\"\n\t\t[placeholder]=\"placeholder ? placeholder : ''\"\n\t\t(blur)=\"touch()\"\n\t\t[disabled]='disabled'\n\t/>\n\t<div class=\"clearIcon\" *ngIf=\"clearable && innerValue?.length > 0\" (click)=\"resetToNull()\">\u00D7</div>\n</div>\n",
569
654
  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: TextInputComponent, multi: true }],
570
- styles: [":host,input{display:block}input{-moz-transition:all .2s ease-in;-ms-transition:all .2s ease-in;-o-transition:all .2s ease-in;-webkit-transition:all .2s ease-in;border:1px solid #e6ecf5;border-radius:2px;box-shadow:none;color:#888da8;font-size:14px;height:42px;outline:none;padding:.375rem .625rem;transition:all .2s ease-in;width:100%}input::-webkit-input-placeholder{color:#adadad}input:-moz-placeholder,input::-moz-placeholder{color:#adadad}input:-ms-input-placeholder{color:#adadad}input:focus{border-color:#3ed778;box-shadow:none;outline:0 none}input.input-sm{height:30px}input.input-lg{height:50px}input.error{background-color:#ffeff4;border-color:#ff3c7e}input.valid{background-color:#ebfaeb;border-color:#37c936;color:#278d26}.showErrors{border-color:#ff8000}"]
655
+ styles: [":host{display:block}:host input:disabled{cursor:not-allowed}.componentContainer{position:relative}i{left:.625rem;position:absolute;top:14px}input{-moz-transition:all .2s ease-in;-ms-transition:all .2s ease-in;-o-transition:all .2s ease-in;-webkit-transition:all .2s ease-in;border:1px solid #e6ecf5;border-radius:2px;box-shadow:none;color:#888da8;display:block;font-size:14px;height:42px;outline:none;padding:.375rem .625rem;transition:all .2s ease-in;width:100%}input::-webkit-input-placeholder{color:#adadad}input:-moz-placeholder,input::-moz-placeholder{color:#adadad}input:-ms-input-placeholder{color:#adadad}input:focus{border-color:#3ed778;box-shadow:none;outline:0 none}input.input-sm{height:30px}input.input-lg{height:50px}input.error{background-color:#ffeff4;border-color:#ff3c7e}input.valid{background-color:#ebfaeb;border-color:#37c936;color:#278d26}input.hasIcon{padding-left:1.875rem}input.hasClearButton{padding-right:1.875rem}.clearIcon{cursor:pointer;font-size:18px;position:absolute;right:.625rem;top:7px}.showErrors{border-color:#ff8000}"]
571
656
  },] }
572
657
  ];
573
658
  TextInputComponent.propDecorators = {
574
659
  placeholder: [{ type: Input }],
575
- type: [{ type: Input }]
660
+ type: [{ type: Input }],
661
+ clearable: [{ type: Input }],
662
+ icon: [{ type: Input }]
576
663
  };
577
664
 
578
665
  class ToggleComponent extends ValueAccessorBase {
@@ -702,33 +789,213 @@ FormSubmitButtonComponent.propDecorators = {
702
789
  _: [{ type: HostBinding, args: ['class._fullWidth',] }]
703
790
  };
704
791
 
792
+ class MultipleValueAccessorBase extends ValueAccessorBase {
793
+ constructor(parent, controlContainer) {
794
+ super(parent, controlContainer);
795
+ this.parent = parent;
796
+ this.controlContainer = controlContainer;
797
+ this.multiple = false;
798
+ }
799
+ writeValue(value) {
800
+ if (this.multiple) {
801
+ if (Array.isArray(value)) {
802
+ super.writeValue(value.filter(isValueSet));
803
+ }
804
+ else {
805
+ super.writeValue([value].filter(isValueSet));
806
+ }
807
+ }
808
+ else {
809
+ if (Array.isArray(value)) {
810
+ super.writeValue(value[0]);
811
+ }
812
+ else {
813
+ super.writeValue(value);
814
+ }
815
+ }
816
+ }
817
+ setInnerValueAndNotify(value) {
818
+ if (this.multiple) {
819
+ if (Array.isArray(value)) {
820
+ super.setInnerValueAndNotify(value.filter(isValueSet));
821
+ }
822
+ else {
823
+ super.setInnerValueAndNotify([value].filter(isValueSet));
824
+ }
825
+ }
826
+ else {
827
+ if (Array.isArray(value)) {
828
+ super.setInnerValueAndNotify(value[0]);
829
+ }
830
+ else {
831
+ super.setInnerValueAndNotify(value);
832
+ }
833
+ }
834
+ }
835
+ }
836
+ MultipleValueAccessorBase.decorators = [
837
+ { type: Component, args: [{
838
+ selector: '',
839
+ template: ''
840
+ },] }
841
+ ];
842
+ MultipleValueAccessorBase.ctorParameters = () => [
843
+ { type: FormElementComponent, decorators: [{ type: Host }, { type: Optional }] },
844
+ { type: ControlContainer, decorators: [{ type: Host }, { type: Optional }] }
845
+ ];
846
+ MultipleValueAccessorBase.propDecorators = {
847
+ multiple: [{ type: Input }]
848
+ };
849
+
705
850
  const invalidDateKey = '--invalid_date--';
706
851
  function dateValidator(control) {
707
852
  const invalid = control.value === invalidDateKey;
708
853
  return invalid ? { date: control.value } : null;
709
854
  }
710
855
 
856
+ const DATE_PICKER_TRANSLATIONS = new InjectionToken('klp.form.date.translations');
857
+ class DatePickerComponent extends MultipleValueAccessorBase {
858
+ constructor(parent, controlContainer, translations) {
859
+ super(parent, controlContainer);
860
+ this.parent = parent;
861
+ this.controlContainer = controlContainer;
862
+ this.translations = translations;
863
+ this.minDate = undefined;
864
+ this.maxDate = undefined;
865
+ this.sameMonthOnly = false;
866
+ this.format = 'dd-MM-yyyy';
867
+ this.clearable = false;
868
+ }
869
+ writeValue(value) {
870
+ if (value === invalidDateKey) {
871
+ super.writeValue(invalidDateKey);
872
+ }
873
+ else if (isNullOrUndefined(value)) {
874
+ this.dateValue = null;
875
+ super.writeValue(null);
876
+ }
877
+ else {
878
+ if (Array.isArray(value)) {
879
+ this.dateValue = value.map((e) => parse(e, 'yyyy-MM-dd', new Date()));
880
+ }
881
+ else {
882
+ this.dateValue = parse(value, 'yyyy-MM-dd', new Date());
883
+ }
884
+ super.writeValue(value);
885
+ }
886
+ }
887
+ dateChanged(value) {
888
+ if (value === invalidDateKey) {
889
+ this.setInnerValueAndNotify(invalidDateKey);
890
+ }
891
+ else if (isNullOrUndefined(value)) {
892
+ this.dateValue = null;
893
+ this.setInnerValueAndNotify(null);
894
+ }
895
+ else {
896
+ this.dateValue = value;
897
+ if (Array.isArray(value)) {
898
+ this.setInnerValueAndNotify(value.map((e) => format(e, 'yyyy-MM-dd')));
899
+ }
900
+ else {
901
+ this.setInnerValueAndNotify(format(value, 'yyyy-MM-dd'));
902
+ }
903
+ }
904
+ }
905
+ getDefaultTranslation(key) {
906
+ switch (key) {
907
+ case 'placeholder':
908
+ return () => { var _a; return (_a = this.placeholder) !== null && _a !== void 0 ? _a : 'Select date'; };
909
+ }
910
+ }
911
+ getTranslation(key, params = null) {
912
+ var _a, _b, _c;
913
+ if (key === 'placeholder' && this.multiple) {
914
+ return '';
915
+ }
916
+ return (_c = (_b = (_a = this.translations) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.call(_a, params)) !== null && _c !== void 0 ? _c : this.getDefaultTranslation(key)(params);
917
+ }
918
+ }
919
+ DatePickerComponent.decorators = [
920
+ { type: Component, args: [{
921
+ selector: 'klp-form-date-picker',
922
+ template: "<div class=\"componentContainer\" [ngClass]=\"{showErrors: isInErrorState()}\">\n\t<klp-form-date-time-picker\n\t\t[multiple]=\"multiple\"\n\t\t[disabled]=\"disabled\"\n\t\t[(ngModel)]=\"dateValue\"\n\t\t(ngModelChange)=\"dateChanged($event)\"\n\t\t[minDate]=\"minDate\"\n\t\t[maxDate]=\"maxDate\"\n\t\t[sameMonthOnly]=\"sameMonthOnly\"\n\t\t[format]=\"format\"\n\t\t[placeholder]=\"getTranslation('placeholder')\"\n\t\t[clearable]=\"clearable\"\n\t\t[showTimeInput]=\"false\"\n\t\t(onTouch)=\"touch()\"\n\t></klp-form-date-time-picker>\n</div>\n",
923
+ providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: DatePickerComponent, multi: true }],
924
+ styles: [":host{display:block}.componentContainer.showErrors ::ng-deep klp-form-date-time-picker .clearButton,.componentContainer.showErrors ::ng-deep klp-form-date-time-picker .dateContainer{border-color:#ff8000}"]
925
+ },] }
926
+ ];
927
+ DatePickerComponent.ctorParameters = () => [
928
+ { type: FormElementComponent, decorators: [{ type: Host }, { type: Optional }] },
929
+ { type: ControlContainer, decorators: [{ type: Host }, { type: Optional }] },
930
+ { type: undefined, decorators: [{ type: Inject, args: [DATE_PICKER_TRANSLATIONS,] }, { type: Optional }] }
931
+ ];
932
+ DatePickerComponent.propDecorators = {
933
+ minDate: [{ type: Input }],
934
+ maxDate: [{ type: Input }],
935
+ sameMonthOnly: [{ type: Input }],
936
+ format: [{ type: Input }],
937
+ placeholder: [{ type: Input }],
938
+ clearable: [{ type: Input }]
939
+ };
940
+
711
941
  const KLP_DATE_FORMATS = new InjectionToken('klp.form.date.formats');
942
+ const DATE_TIME_PICKER_TRANSLATIONS = new InjectionToken('klp.form.dateTime.translations');
712
943
  function matDateFormatsFactory(component, dateFormats) {
713
944
  var _a;
714
945
  return (_a = dateFormats === null || dateFormats === void 0 ? void 0 : dateFormats(component.format)) !== null && _a !== void 0 ? _a : MAT_NATIVE_DATE_FORMATS;
715
946
  }
716
- class DatepickerComponent extends ValueAccessorBase {
717
- constructor() {
718
- super(...arguments);
947
+ class DateTimePickerComponent extends MultipleValueAccessorBase {
948
+ constructor(parent, controlContainer, translations, cdr) {
949
+ super(parent, controlContainer);
950
+ this.parent = parent;
951
+ this.controlContainer = controlContainer;
952
+ this.translations = translations;
953
+ this.cdr = cdr;
719
954
  this.minDate = undefined;
720
955
  this.maxDate = undefined;
721
- this.placeholder = 'Select date';
956
+ this.sameMonthOnly = false;
957
+ this.format = 'dd-MM-yyyy';
722
958
  this.clearable = false;
959
+ this.showTimeInput = true;
960
+ this.invalidTimeAsMidnight = false; // if the time is not valid, use 00:00 as the time
723
961
  this.minDateStartOfDay = undefined;
724
962
  this.maxDateEndOfDay = undefined;
963
+ this.selectedDates = [];
964
+ this.dateTouched = false;
965
+ this.hoursTouched = false;
966
+ this.minutesTouched = false;
967
+ this.isSelected = (d) => {
968
+ if (this.multiple) {
969
+ return this.selectedDates.some((e) => e.getTime() === d.getTime()) ? 'selected' : '';
970
+ }
971
+ return '';
972
+ };
973
+ this.filterDates = (e) => {
974
+ if (this.disabled) {
975
+ return false;
976
+ }
977
+ return true;
978
+ };
979
+ }
980
+ ngOnInit() {
981
+ super.ngOnInit();
982
+ if (this.multiple) {
983
+ this.placeholder = '';
984
+ this.showTimeInput = false;
985
+ }
986
+ }
987
+ ngAfterViewInit() {
988
+ if (this.multiple) {
989
+ // we are going to overwrite the datepicker closing fn later, so we are saving it here to restore it when needed
990
+ this.datePickingClosingFn = this.datePickerRef.close;
991
+ }
725
992
  }
726
993
  ngOnChanges(changes) {
727
994
  if (changes.minDate) {
728
- this.setMinDate(changes.minDate.currentValue);
995
+ this.determineMinAndMaxDates();
729
996
  }
730
997
  if (changes.maxDate) {
731
- this.setMaxDate(changes.maxDate.currentValue);
998
+ this.determineMinAndMaxDates();
732
999
  }
733
1000
  }
734
1001
  setMinDate(minDate) {
@@ -749,66 +1016,227 @@ class DatepickerComponent extends ValueAccessorBase {
749
1016
  this.maxDateEndOfDay = undefined;
750
1017
  }
751
1018
  }
1019
+ getSelectedMonths() {
1020
+ return removeDuplicatesFromArray(this.selectedDates.map((e) => format(e, 'MMMM'))).length;
1021
+ }
752
1022
  // dateChanged is called when the output of the datepicker is changed and
753
1023
  // parsed correctly. If the date is invalid, it will be called the first time
754
1024
  // with null but never again until a valid input is provided.
755
1025
  dateChanged(event) {
756
- const nativeInputValue = this.nativeInputRef.nativeElement.value;
757
1026
  const date = event.value;
758
- if (isNullOrUndefined(date) && stringIsSetAndNotEmpty(nativeInputValue)) {
759
- this.setInnerValueAndNotify(invalidDateKey);
1027
+ if (this.multiple) {
1028
+ this.datePickerRef.close = () => {
1029
+ };
1030
+ if (this.selectedDates.some((e) => e.getTime() === date.getTime())) {
1031
+ this.selectedDates = this.selectedDates.filter((e) => e.getTime() !== date.getTime());
1032
+ }
1033
+ else {
1034
+ this.selectedDates = [...this.selectedDates, date];
1035
+ }
1036
+ // START HACK
1037
+ // the date picker does not provide any rerender calls. Therefore, we are going to change the minDate in order to force the render
1038
+ // This is needed to show all selected days in our date picker
1039
+ // We also set the innerValue to null (with this.valueForMaterialDatePicker = null;), otherwise you can not
1040
+ // deselect your last picked date
1041
+ this.cdr.detectChanges();
1042
+ this.valueForMaterialDatePicker = null;
1043
+ const oldMinDate = this.minDateStartOfDay;
1044
+ this.minDateStartOfDay = new Date(0);
1045
+ this.cdr.detectChanges();
1046
+ this.minDateStartOfDay = oldMinDate;
1047
+ // END HACK
1048
+ if (this.sameMonthOnly) {
1049
+ if (this.selectedDates.length >= 2) {
1050
+ if (date < startOfMonth(this.selectedDates[0]) || date > endOfMonth(this.selectedDates[0])) {
1051
+ this.selectedDates = [date];
1052
+ }
1053
+ }
1054
+ this.determineMinAndMaxDates();
1055
+ }
1056
+ this.setInnerValueAndNotify(this.selectedDates);
1057
+ setTimeout(() => {
1058
+ this.datePickerRef.close = this.datePickingClosingFn;
1059
+ });
1060
+ }
1061
+ else {
1062
+ this.notifyNewDate();
1063
+ }
1064
+ }
1065
+ determineMinAndMaxDates() {
1066
+ if (this.sameMonthOnly) {
1067
+ if (this.selectedDates.length >= 2) {
1068
+ this.setMinDate(startOfMonth(this.selectedDates[0]));
1069
+ this.setMaxDate(endOfMonth(this.selectedDates[0]));
1070
+ }
1071
+ else {
1072
+ this.setMinDate(this.minDate);
1073
+ this.setMaxDate(this.maxDate);
1074
+ }
760
1075
  }
761
1076
  else {
762
- this.setInnerValueAndNotify(date);
1077
+ this.setMinDate(this.minDate);
1078
+ this.setMinDate(this.maxDate);
1079
+ }
1080
+ }
1081
+ notifyNewDate() {
1082
+ const nativeInputValue = this.nativeInputRef.nativeElement.value;
1083
+ const parsedHours = Number(this.hours);
1084
+ const parsedMinutes = Number(this.minutes);
1085
+ // if we dont have the time element
1086
+ if (!this.showTimeInput) {
1087
+ if (!stringIsSetAndFilled(nativeInputValue)) {
1088
+ this.setInnerValueAndNotify(null);
1089
+ return;
1090
+ }
1091
+ if (this.valueForMaterialDatePicker instanceof Date) {
1092
+ this.setInnerValueAndNotify(this.valueForMaterialDatePicker);
1093
+ return;
1094
+ }
763
1095
  }
1096
+ // when all inputs are empty
1097
+ if (!stringIsSetAndFilled(nativeInputValue) && !stringIsSetAndFilled(this.hours) && !stringIsSetAndFilled(this.minutes)) {
1098
+ this.setInnerValueAndNotify(null);
1099
+ return;
1100
+ }
1101
+ // if we have date and time
1102
+ if (stringIsSetAndFilled(this.hours) &&
1103
+ Number.isFinite(parsedHours) &&
1104
+ parsedHours >= 0 &&
1105
+ parsedHours <= 23 &&
1106
+ stringIsSetAndFilled(this.minutes) &&
1107
+ Number.isFinite(parsedMinutes) &&
1108
+ parsedMinutes >= 0 &&
1109
+ parsedMinutes <= 59 &&
1110
+ this.valueForMaterialDatePicker instanceof Date) {
1111
+ const newDateWithHours = new Date(this.valueForMaterialDatePicker.setHours(parsedHours));
1112
+ const newDateWithMinutes = new Date(newDateWithHours.setMinutes(parsedMinutes));
1113
+ this.setInnerValueAndNotify(newDateWithMinutes);
1114
+ return;
1115
+ }
1116
+ if (this.invalidTimeAsMidnight) {
1117
+ if (this.valueForMaterialDatePicker instanceof Date) {
1118
+ this.setInnerValueAndNotify(this.valueForMaterialDatePicker);
1119
+ return;
1120
+ }
1121
+ }
1122
+ // all other cases, we are not in a valid state
1123
+ this.setInnerValueAndNotify(invalidDateKey);
764
1124
  }
765
1125
  writeValue(value) {
766
1126
  super.writeValue(value);
767
- this.valueForMaterialDatePicker = value === invalidDateKey ? null : value;
1127
+ if (Array.isArray(value)) {
1128
+ this.selectedDates = value;
1129
+ this.determineMinAndMaxDates();
1130
+ this.valueForMaterialDatePicker = null;
1131
+ }
1132
+ else {
1133
+ this.valueForMaterialDatePicker = value === invalidDateKey ? null : value;
1134
+ if (value instanceof Date) {
1135
+ this.hours = String(value.getHours());
1136
+ this.minutes = String(value.getMinutes());
1137
+ this.formatTime();
1138
+ }
1139
+ else {
1140
+ this.hours = '';
1141
+ this.minutes = '';
1142
+ }
1143
+ }
768
1144
  }
769
1145
  // nativeValueChanged is called when the internal text value changes, but not
770
1146
  // when the date is changed via the date picker. We need this so that we can
771
1147
  // determine if the datepicker is empty or invalid.
772
- nativeValueChanged(event) {
773
- const nativeInputValue = event.target.value;
774
- const date = this.valueForMaterialDatePicker;
1148
+ nativeValueChanged() {
775
1149
  if (this.datePickerRef.opened) {
776
1150
  // if the user is typing instead of using the picker, close it.
777
1151
  this.datePickerRef.close();
778
1152
  }
779
- if (isNullOrUndefined(date) && stringIsSetAndNotEmpty(nativeInputValue)) {
780
- this.setInnerValueAndNotify(invalidDateKey);
781
- }
782
- else {
783
- this.setInnerValueAndNotify(date);
784
- }
1153
+ this.notifyNewDate();
785
1154
  }
786
1155
  resetToNull() {
787
1156
  this.setInnerValueAndNotify(null);
788
1157
  this.valueForMaterialDatePicker = null;
789
1158
  this.nativeInputRef.nativeElement.value = null;
1159
+ this.hours = '';
1160
+ this.minutes = '';
1161
+ this.selectedDates = [];
1162
+ }
1163
+ formatTime() {
1164
+ if (Number.isFinite(Number(this.hours)) && this.hours.length === 1) {
1165
+ this.hours = '0' + this.hours;
1166
+ }
1167
+ if (Number.isFinite(Number(this.minutes)) && this.minutes.length === 1) {
1168
+ this.minutes = '0' + this.minutes;
1169
+ }
1170
+ }
1171
+ touchDate() {
1172
+ this.dateTouched = true;
1173
+ this.determineAllTouched();
1174
+ }
1175
+ touchHours() {
1176
+ this.hoursTouched = true;
1177
+ this.determineAllTouched();
1178
+ }
1179
+ touchMinutes() {
1180
+ this.minutesTouched = true;
1181
+ this.determineAllTouched();
1182
+ }
1183
+ determineAllTouched() {
1184
+ if ((this.dateTouched && this.hoursTouched && this.minutesTouched) || (this.dateTouched && !this.showTimeInput)) {
1185
+ this.touch();
1186
+ }
1187
+ }
1188
+ getDefaultTranslation(key) {
1189
+ switch (key) {
1190
+ case 'placeholder':
1191
+ return () => { var _a; return (_a = this.placeholder) !== null && _a !== void 0 ? _a : 'Select date'; };
1192
+ case 'selectDays':
1193
+ return () => 'Select day(s)';
1194
+ case 'selectedDate':
1195
+ return (d) => d.toLocaleDateString();
1196
+ case 'daysSelected':
1197
+ return (amount) => `${amount} days selected`;
1198
+ case 'selectedInMonth':
1199
+ return (d) => ` in ${format(d, 'MMMM')}`;
1200
+ }
1201
+ }
1202
+ getTranslation(key, params = null) {
1203
+ var _a, _b, _c;
1204
+ if (key === 'placeholder' && this.multiple) {
1205
+ return '';
1206
+ }
1207
+ return (_c = (_b = (_a = this.translations) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.call(_a, params)) !== null && _c !== void 0 ? _c : this.getDefaultTranslation(key)(params);
790
1208
  }
791
1209
  }
792
- DatepickerComponent.decorators = [
1210
+ DateTimePickerComponent.decorators = [
793
1211
  { type: Component, args: [{
794
- selector: 'klp-form-datepicker',
795
- template: "<div class=\"componentContainer\" [ngClass]=\"{showErrors: isInErrorState()}\">\n\t<mat-form-field [floatLabel]=\"'never'\">\n\t\t<input\n\t\t\t#nativeInput\n\t\t\tmatInput\n\t\t\t[matDatepicker]=\"picker\"\n\t\t\t[(ngModel)]=\"valueForMaterialDatePicker\"\n\t\t\t(dateInput)=\"dateChanged($event)\"\n\t\t\t(input)=\"nativeValueChanged($event)\"\n\t\t\t[min]=\"minDateStartOfDay\"\n\t\t\t[max]=\"maxDateEndOfDay\"\n\t\t\t[placeholder]=\"placeholder\"\n\t\t\t(click)=\"picker.open()\"\n\t\t\t(blur)=\"touch()\"\n\t\t>\n\t\t<mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n\t\t<mat-datepicker #picker\n\t\t></mat-datepicker>\n\t</mat-form-field>\n\t<button *ngIf=\"clearable\" class=\"clearButton\" (click)=\"resetToNull()\">\u00D7</button>\n</div>\n",
1212
+ selector: 'klp-form-date-time-picker',
1213
+ template: "<div class=\"componentContainer\" [ngClass]=\"{showErrors: isInErrorState()}\">\n\t<div class=\"dateContainer\" [ngClass]=\"{noRightBorder: !showTimeInput && clearable && !disabled, disabled: disabled}\">\n\t\t<mat-form-field floatLabel=\"never\">\n\t\t\t<div *ngIf=\"multiple\" class=\"daysSelectedCaption\" (click)=\"picker.open()\" [ngClass]=\"{disabled: disabled}\">\n\t\t\t\t<ng-container *ngIf=\"selectedDates.length >= 2\">\n\t\t\t\t\t<span>{{getTranslation('daysSelected', selectedDates.length)}}</span>\n\t\t\t\t\t<span *ngIf=\"getSelectedMonths() === 1\">{{getTranslation('selectedInMonth', selectedDates[0])}}</span>\n\t\t\t\t</ng-container>\n\t\t\t\t<span *ngIf=\"selectedDates.length === 1\">{{getTranslation('selectedDate', selectedDates[0])}}</span>\n\t\t\t\t<span *ngIf=\"selectedDates.length === 0\" class=\"placeholderForMultipleSelection\">{{getTranslation('selectDays')}}</span>\n\t\t\t</div>\n\t\t\t<input\n\t\t\t\t#nativeInput\n\t\t\t\tmatInput\n\t\t\t\t[matDatepicker]=\"picker\"\n\t\t\t\t[matDatepickerFilter]=\"filterDates\"\n\t\t\t\t[(ngModel)]=\"valueForMaterialDatePicker\"\n\t\t\t\t(dateInput)=\"dateChanged($event)\"\n\t\t\t\t(input)=\"nativeValueChanged()\"\n\t\t\t\t[min]=\"minDateStartOfDay\"\n\t\t\t\t[max]=\"maxDateEndOfDay\"\n\t\t\t\t[placeholder]=\"getTranslation('placeholder')\"\n\t\t\t\t(click)=\"picker.open()\"\n\t\t\t\t(blur)=\"touchDate()\"\n\t\t\t\t[ngClass]=\"{inputForMultipleDays: multiple}\"\n\t\t\t>\n\t\t\t<mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n\t\t\t<mat-datepicker\n\t\t\t\t#picker\n\t\t\t\t[dateClass]=\"isSelected\"\n\t\t\t></mat-datepicker>\n\t\t</mat-form-field>\n\t</div>\n\t<div class=\"timeContainer\" *ngIf=\"showTimeInput\" [ngClass]=\"{disabled: disabled}\">\n\t\t<input maxlength=\"2\" placeholder=\"__\" [disabled]=\"disabled\" [(ngModel)]=\"hours\" (ngModelChange)=\"notifyNewDate()\" (blur)=\"formatTime(); touchHours()\">\n\t\t<div class=\"divider\">:</div>\n\t\t<input maxlength=\"2\" placeholder=\"__\" [disabled]=\"disabled\" [(ngModel)]=\"minutes\" (ngModelChange)=\"notifyNewDate()\" (blur)=\"formatTime(); touchMinutes()\">\n\t</div>\n\t<button *ngIf=\"clearable && !disabled\" class=\"clearButton\" (click)=\"resetToNull()\" [ngClass]=\"{withoutSpacing: !showTimeInput}\">\u00D7</button>\n</div>\n",
796
1214
  providers: [
797
- { provide: NG_VALUE_ACCESSOR, useExisting: DatepickerComponent, multi: true },
798
- { provide: MAT_DATE_FORMATS,
799
- deps: [DatepickerComponent, [new Optional(), KLP_DATE_FORMATS]],
1215
+ { provide: NG_VALUE_ACCESSOR, useExisting: DateTimePickerComponent, multi: true },
1216
+ {
1217
+ provide: MAT_DATE_FORMATS,
1218
+ deps: [DateTimePickerComponent, [new Optional(), KLP_DATE_FORMATS]],
800
1219
  useFactory: matDateFormatsFactory,
801
1220
  }
802
1221
  ],
803
- styles: [":host{display:block}:host ::ng-deep mat-form-field{display:block;height:100%}:host ::ng-deep mat-form-field.mat-focused .mat-form-field-label,:host ::ng-deep mat-form-field .mat-form-field-label{color:#adadad}:host ::ng-deep .mat-datepicker-toggle-active{color:#666}:host ::ng-deep .mat-form-field-wrapper{padding-bottom:none}:host ::ng-deep .mat-form-field-flex{flex-direction:row-reverse}:host ::ng-deep .mat-form-field-infix{border-top:none}:host ::ng-deep .mat-form-field-suffix{margin-right:.625rem}:host ::ng-deep .mat-form-field-suffix:hover .mat-button-focus-overlay{opacity:.1}:host ::ng-deep .mat-form-field-underline{display:none}.componentContainer{-moz-transition:all .2s ease-in;-ms-transition:all .2s ease-in;-o-transition:all .2s ease-in;-webkit-transition:all .2s ease-in;border:1px solid #e6ecf5;border-radius:2px;box-shadow:none;color:#888da8;display:block;font-size:14px;height:42px;padding:.375rem .625rem;position:relative;transition:all .2s ease-in;width:100%}.componentContainer::-webkit-input-placeholder{color:#adadad}.componentContainer:-moz-placeholder,.componentContainer::-moz-placeholder{color:#adadad}.componentContainer:-ms-input-placeholder{color:#adadad}.componentContainer:focus{border-color:#3ed778;box-shadow:none;outline:0 none}.componentContainer.input-sm{height:30px}.componentContainer.input-lg{height:50px}.componentContainer.error{background-color:#ffeff4;border-color:#ff3c7e}.componentContainer.valid{background-color:#ebfaeb;border-color:#37c936;color:#278d26}.componentContainer.showErrors{border-color:#ff8000}.componentContainer .clearButton{align-items:center;background:none;border:none;bottom:0;color:#7b7b7b;display:flex;font-size:18px;position:absolute;right:1.25rem;top:0}"]
1222
+ styles: [":host{display:block}:host ::ng-deep mat-form-field{display:block;height:100%}:host ::ng-deep mat-form-field.mat-focused .mat-form-field-label,:host ::ng-deep mat-form-field .mat-form-field-label{color:#adadad}:host ::ng-deep .mat-datepicker-toggle-active{color:#666}:host ::ng-deep .mat-form-field-wrapper{padding-bottom:0}:host ::ng-deep .mat-form-field-flex{flex-direction:row-reverse}:host ::ng-deep .mat-form-field-infix{border-top:none;width:auto}:host ::ng-deep .mat-form-field-suffix{margin-right:.625rem}:host ::ng-deep .mat-form-field-suffix:hover .mat-button-focus-overlay{opacity:.1}:host ::ng-deep .mat-form-field-underline{display:none}:host ::ng-deep .daysSelectedCaption{cursor:pointer}:host ::ng-deep .daysSelectedCaption.disabled{cursor:zoom-in}:host ::ng-deep .inputForMultipleDays{display:none}.componentContainer{border-radius:2px;color:#888da8;display:flex;position:relative}.componentContainer .placeholderForMultipleSelection{color:#adadad}.componentContainer.showErrors .clearButton.withoutSpacing,.componentContainer.showErrors .dateContainer,.componentContainer.showErrors .timeContainer{border-color:#ff8000}.componentContainer .clearButton{align-items:center;background:#fff;border:1px solid #e6ecf5;color:#7b7b7b;display:flex;flex:0 0 auto;font-size:18px;margin-left:1.25rem;padding:6px 14px}.componentContainer .clearButton.withoutSpacing{border-left:none;margin-left:0}.componentContainer .clearButton:disabled{background:#f9f9f9;border:1px solid #e6ecf5}.componentContainer .dateContainer{background:#fff;border:1px solid #e6ecf5;flex:1 1 auto;padding:6px}.componentContainer .dateContainer.noRightBorder{border-right:none}.componentContainer .dateContainer.disabled{background:#f9f9f9}.componentContainer .timeContainer{align-items:center;background:#fff;border:1px solid #e6ecf5;display:flex;flex:0 0 auto;margin-left:1.25rem;padding:6px .625rem}.componentContainer .timeContainer.disabled{background:#f9f9f9}.componentContainer .timeContainer input{border:none;color:#888da8;padding:0;text-align:center;width:20px}.componentContainer .timeContainer input::-moz-placeholder{color:#adadad}.componentContainer .timeContainer input:-ms-input-placeholder{color:#adadad}.componentContainer .timeContainer input::placeholder{color:#adadad}.componentContainer .timeContainer .divider{margin:0 .3125rem}"]
804
1223
  },] }
805
1224
  ];
806
- DatepickerComponent.propDecorators = {
1225
+ DateTimePickerComponent.ctorParameters = () => [
1226
+ { type: FormElementComponent, decorators: [{ type: Host }, { type: Optional }] },
1227
+ { type: ControlContainer, decorators: [{ type: Host }, { type: Optional }] },
1228
+ { type: undefined, decorators: [{ type: Inject, args: [DATE_TIME_PICKER_TRANSLATIONS,] }, { type: Optional }] },
1229
+ { type: ChangeDetectorRef }
1230
+ ];
1231
+ DateTimePickerComponent.propDecorators = {
807
1232
  minDate: [{ type: Input }],
808
1233
  maxDate: [{ type: Input }],
1234
+ sameMonthOnly: [{ type: Input }],
809
1235
  format: [{ type: Input }],
810
1236
  placeholder: [{ type: Input }],
811
1237
  clearable: [{ type: Input }],
1238
+ showTimeInput: [{ type: Input }],
1239
+ invalidTimeAsMidnight: [{ type: Input }],
812
1240
  nativeInputRef: [{ type: ViewChild, args: ['nativeInput',] }],
813
1241
  datePickerRef: [{ type: ViewChild, args: ['picker',] }]
814
1242
  };
@@ -837,14 +1265,17 @@ NgxEnhancyFormsModule.decorators = [
837
1265
  ],
838
1266
  declarations: [
839
1267
  ValueAccessorBase,
1268
+ MultipleValueAccessorBase,
840
1269
  ButtonComponent,
841
1270
  CheckboxComponent,
842
- DatepickerComponent,
1271
+ DatePickerComponent,
1272
+ DateTimePickerComponent,
843
1273
  EmailInputComponent,
844
1274
  LoadingIndicatorComponent,
845
1275
  NumberInputComponent,
846
1276
  PasswordFieldComponent,
847
1277
  SelectComponent,
1278
+ SelectFooterComponent,
848
1279
  SortableItemsComponent,
849
1280
  TextInputComponent,
850
1281
  ToggleComponent,
@@ -857,14 +1288,17 @@ NgxEnhancyFormsModule.decorators = [
857
1288
  ],
858
1289
  exports: [
859
1290
  ValueAccessorBase,
1291
+ MultipleValueAccessorBase,
860
1292
  ButtonComponent,
861
- DatepickerComponent,
1293
+ DatePickerComponent,
1294
+ DateTimePickerComponent,
862
1295
  CheckboxComponent,
863
1296
  EmailInputComponent,
864
1297
  LoadingIndicatorComponent,
865
1298
  NumberInputComponent,
866
1299
  PasswordFieldComponent,
867
1300
  SelectComponent,
1301
+ SelectFooterComponent,
868
1302
  SortableItemsComponent,
869
1303
  TextInputComponent,
870
1304
  ToggleComponent,
@@ -886,5 +1320,5 @@ NgxEnhancyFormsModule.decorators = [
886
1320
  * Generated bundle index. Do not edit.
887
1321
  */
888
1322
 
889
- export { ButtonComponent, CheckboxComponent, DEFAULT_ERROR_MESSAGES, DatepickerComponent, EmailInputComponent, FORM_ERROR_MESSAGES, FormCaptionComponent, FormComponent, FormElementComponent, FormErrorComponent, FormSubmitButtonComponent, KLP_DATE_FORMATS, LoadingIndicatorComponent, NgxEnhancyFormsModule, NumberInputComponent, PasswordFieldComponent, SelectComponent, SortableItemsComponent, SubFormDirective, TextInputComponent, ToggleComponent, ValueAccessorBase, dateValidator, invalidDateKey, invalidFieldsSymbol, matDateFormatsFactory, MaterialModule as ɵa };
1323
+ export { ButtonComponent, CheckboxComponent, DATE_PICKER_TRANSLATIONS, DATE_TIME_PICKER_TRANSLATIONS, DEFAULT_ERROR_MESSAGES, DatePickerComponent, DateTimePickerComponent, EmailInputComponent, FORM_ERROR_MESSAGES, FormCaptionComponent, FormComponent, FormElementComponent, FormErrorComponent, FormSubmitButtonComponent, KLP_DATE_FORMATS, LoadingIndicatorComponent, MultipleValueAccessorBase, NgxEnhancyFormsModule, NumberInputComponent, PasswordFieldComponent, SELECT_TRANSLATIONS, SelectComponent, SelectFooterComponent, SortableItemsComponent, SubFormDirective, TextInputComponent, ToggleComponent, ValueAccessorBase, dateValidator, invalidDateKey, invalidFieldsSymbol, matDateFormatsFactory, MaterialModule as ɵa };
890
1324
  //# sourceMappingURL=klippa-ngx-enhancy-forms.js.map