@vaadin/vaadin-date-picker 4.5.0 → 4.6.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.
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "repository": "vaadin/vaadin-date-picker",
11
11
  "homepage": "https://vaadin.com/components",
12
12
  "name": "@vaadin/vaadin-date-picker",
13
- "version": "4.5.0",
13
+ "version": "4.6.0",
14
14
  "main": "vaadin-date-picker.js",
15
15
  "author": "Vaadin Ltd",
16
16
  "license": "Apache-2.0",
@@ -37,7 +37,7 @@
37
37
  "@polymer/iron-resizable-behavior": "^3.0.0",
38
38
  "@polymer/polymer": "^3.0.0",
39
39
  "@vaadin/vaadin-button": "^2.4.0",
40
- "@vaadin/vaadin-text-field": "^2.8.0",
40
+ "@vaadin/vaadin-text-field": "^2.10.0",
41
41
  "@vaadin/vaadin-themable-mixin": "^1.6.1",
42
42
  "@vaadin/vaadin-control-state-mixin": "^2.2.2",
43
43
  "@vaadin/vaadin-overlay": "^3.5.0",
@@ -72,8 +72,14 @@ declare class DatePickerLightElement extends
72
72
  ThemableMixin(
73
73
  DatePickerMixin(
74
74
  PolymerElement)) {
75
+
76
+ /**
77
+ * The method is overridden to allow the customization of
78
+ * the input element value property name, which can be
79
+ * achieved by providing a custom `attrForValue` property.
80
+ */
81
+ readonly _inputElementValueProperty: string;
75
82
  _overlayInitialized: boolean;
76
- _inputValue: string|undefined;
77
83
 
78
84
  /**
79
85
  * Name of the two-way data-bindable property representing the
@@ -130,15 +130,17 @@ class DatePickerLightElement extends
130
130
  return this.querySelector('vaadin-text-field,iron-input,paper-input,.paper-input-input,.input');
131
131
  }
132
132
 
133
- set _inputValue(value) {
134
- if (this._inputElement) {
135
- this._inputElement[dashToCamelCase(this.attrForValue)] = value;
136
- }
137
- }
138
-
139
- /** @return {string | undefined} */
140
- get _inputValue() {
141
- return this._inputElement && this._inputElement[dashToCamelCase(this.attrForValue)];
133
+ /**
134
+ * The method is overridden to allow the customization of
135
+ * the input element value property name, which can be
136
+ * achieved by providing a custom `attrForValue` property.
137
+ *
138
+ * @protected
139
+ * @override
140
+ * @return {string}
141
+ */
142
+ get _inputElementValueProperty() {
143
+ return dashToCamelCase(this.attrForValue);
142
144
  }
143
145
  }
144
146
 
@@ -33,6 +33,18 @@ export {DatePickerMixinConstructor};
33
33
  interface DatePickerMixin {
34
34
  readonly _inputElement: HTMLElement|null;
35
35
 
36
+ /**
37
+ * A property for accessing the input element's value.
38
+ *
39
+ * Override this getter if the property is different from the default `value` one.
40
+ */
41
+ readonly _inputElementValueProperty: string;
42
+
43
+ /**
44
+ * The input element's value.
45
+ */
46
+ _inputElementValue: string;
47
+
36
48
  /**
37
49
  * The current selected date.
38
50
  */
@@ -204,6 +216,14 @@ interface DatePickerMixin {
204
216
  * The latest date that can be selected. All later dates will be disabled.
205
217
  */
206
218
  _maxDate: Date|string|null;
219
+
220
+ /**
221
+ * The property indicates true only if the input has been entered by the user.
222
+ * In the case of programmatic changes, the property is reset to false.
223
+ * Read more about why this workaround is needed:
224
+ * https://github.com/vaadin/web-components/issues/5639
225
+ */
226
+ _hasInputValue: boolean|null|undefined;
207
227
  _overlayInitialized: boolean|null|undefined;
208
228
  ready(): void;
209
229
  disconnectedCallback(): void;
@@ -219,11 +239,19 @@ interface DatePickerMixin {
219
239
  close(): void;
220
240
  _onOverlayOpened(): void;
221
241
  _onOverlayClosed(): void;
242
+ _setInvalid(invalid: boolean): void;
243
+
244
+ /**
245
+ * Override this method to define whether the given `invalid` state should be set.
246
+ */
247
+ _shouldSetInvalid(_invalid: boolean): boolean;
222
248
 
223
249
  /**
224
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
250
+ * Validates the field and sets the `invalid` property based on the result.
225
251
  *
226
- * @returns True if the value is valid and sets the `invalid` flag appropriately
252
+ * The method fires a `validated` event with the result of the validation.
253
+ *
254
+ * @returns True if the value is valid.
227
255
  */
228
256
  validate(): boolean;
229
257
 
@@ -236,6 +264,11 @@ interface DatePickerMixin {
236
264
  */
237
265
  checkValidity(): boolean;
238
266
  _focus(): void;
267
+
268
+ /**
269
+ * Sets the `_hasInputValue` property based on the `input` event.
270
+ */
271
+ _setHasInputValue(event: InputEvent|null): void;
239
272
  }
240
273
 
241
274
  import {DatePickerI18n} from '../@types/interfaces';
@@ -332,6 +332,20 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
332
332
  computed: '_isNoInput(_fullscreen, _ios, i18n, i18n.*, opened, autoOpenDisabled)'
333
333
  },
334
334
 
335
+ /**
336
+ * The property indicates true only if the input has been entered by the user.
337
+ * In the case of programmatic changes, the property is reset to false.
338
+ * Read more about why this workaround is needed:
339
+ * https://github.com/vaadin/web-components/issues/5639
340
+ *
341
+ * @protected
342
+ */
343
+ _hasInputValue: {
344
+ type: Boolean,
345
+ value: false,
346
+ observer: '_hasInputValueChanged',
347
+ },
348
+
335
349
  /** @private */
336
350
  _ios: {
337
351
  type: Boolean,
@@ -397,7 +411,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
397
411
  }
398
412
  });
399
413
  this.addEventListener('keydown', this._onKeydown.bind(this));
400
- this.addEventListener('input', this._onUserInput.bind(this));
414
+ this.addEventListener('input', this.__onUserInput.bind(this));
401
415
  this.addEventListener('focus', e => this._noInput && e.target.blur());
402
416
  this.addEventListener('blur', e => {
403
417
  if (!this.opened) {
@@ -408,7 +422,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
408
422
  }
409
423
  }
410
424
 
411
- if (this._inputElement.value === '' && this.__dispatchChange) {
425
+ if (this._inputElementValue === '' && this.__dispatchChange) {
412
426
  this.validate();
413
427
  this.value = '';
414
428
  this.__dispatchChange = false;
@@ -774,7 +788,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
774
788
  // Select the parsed input or focused date
775
789
  this._ignoreFocusedDateChange = true;
776
790
  if (this.i18n.parseDate) {
777
- const inputValue = this._inputValue || '';
791
+ const inputValue = this._inputElementValue || '';
778
792
  const parsedDate = this._getParsedDate(inputValue);
779
793
 
780
794
  if (this._isValidDate(parsedDate)) {
@@ -818,16 +832,80 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
818
832
  }
819
833
 
820
834
  /**
821
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
835
+ * A property for accessing the input element's value.
836
+ *
837
+ * Override this getter if the property is different from the default `value` one.
822
838
  *
823
- * @param {string=} value Value to validate. Optional, defaults to user's input value.
824
- * @return {boolean} True if the value is valid and sets the `invalid` flag appropriately
839
+ * @protected
840
+ * @return {string}
841
+ */
842
+ get _inputElementValueProperty() {
843
+ return 'value';
844
+ }
845
+
846
+ /**
847
+ * The input element's value.
848
+ *
849
+ * @protected
850
+ * @return {string}
851
+ */
852
+ get _inputElementValue() {
853
+ return this._inputElement ? this._inputElement[this._inputElementValueProperty] : undefined;
854
+ }
855
+
856
+ /**
857
+ * The setter resets the `_hasInputValue` property
858
+ * to false when the input element's value is updated programmatically.
859
+ * In date-picker, `_hasInputValue` is supposed to indicate true only
860
+ * if the input has been entered by the user.
861
+ * Read more about why this workaround is needed:
862
+ * https://github.com/vaadin/web-components/issues/5639
863
+ *
864
+ * @protected
865
+ */
866
+ set _inputElementValue(value) {
867
+ if (this._inputElement) {
868
+ this._inputElement[this._inputElementValueProperty] = value;
869
+ this._hasInputValue = false;
870
+ }
871
+ }
872
+
873
+ /**
874
+ * @param {boolean} invalid
875
+ * @protected
876
+ */
877
+ _setInvalid(invalid) {
878
+ if (this._shouldSetInvalid(invalid)) {
879
+ this.invalid = invalid;
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Override this method to define whether the given `invalid` state should be set.
885
+ *
886
+ * @param {boolean} _invalid
887
+ * @return {boolean}
888
+ * @protected
889
+ */
890
+ _shouldSetInvalid(_invalid) {
891
+ return true;
892
+ }
893
+
894
+ /**
895
+ * Validates the field and sets the `invalid` property based on the result.
896
+ *
897
+ * The method fires a `validated` event with the result of the validation.
898
+ *
899
+ * @return {boolean} True if the value is valid.
825
900
  */
826
901
  validate() {
827
- // Note (Yuriy): Workaround `this._inputValue` is used in order
828
- // to avoid breaking change on custom `checkValidity`.
829
- // Can be removed with next major.
830
- return !(this.invalid = !this.checkValidity(this._inputValue));
902
+ // Note (Yuriy): this._inputElementValue is passed to checkValidity() as an argument to maintain
903
+ // backward compatibility in case it's being used in a custom implementation of checkValidity().
904
+ // The workaround can be removed with the next major.
905
+ const isValid = this.checkValidity(this._inputElementValue);
906
+ this._setInvalid(!isValid);
907
+ this.dispatchEvent(new CustomEvent('validated', {detail: {valid: isValid}}));
908
+ return isValid;
831
909
  }
832
910
 
833
911
  /**
@@ -839,8 +917,8 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
839
917
  * @return {boolean} True if the value is valid
840
918
  */
841
919
  checkValidity() {
842
- const inputValid = !this._inputValue ||
843
- (this._selectedDate && this._inputValue === this._getFormattedDate(this.i18n.formatDate, this._selectedDate));
920
+ const inputValid = !this._inputElementValue ||
921
+ (this._selectedDate && this._inputElementValue === this._getFormattedDate(this.i18n.formatDate, this._selectedDate));
844
922
  const minMaxValid = !this._selectedDate ||
845
923
  DatePickerHelper._dateAllowed(this._selectedDate, this._minDate, this._maxDate);
846
924
 
@@ -857,7 +935,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
857
935
  }
858
936
  }
859
937
 
860
- return inputValid && minMaxValid && inputValidity;
938
+ return !!(inputValid && minMaxValid && inputValidity);
861
939
  }
862
940
 
863
941
  /** @private */
@@ -879,12 +957,12 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
879
957
  /** @private */
880
958
  _focusAndSelect() {
881
959
  this._focus();
882
- this._setSelectionRange(0, this._inputValue.length);
960
+ this._setSelectionRange(0, this._inputElementValue.length);
883
961
  }
884
962
 
885
963
  /** @private */
886
964
  _applyInputValue(date) {
887
- this._inputValue = date ? this._getFormattedDate(this.i18n.formatDate, date) : '';
965
+ this._inputElementValue = date ? this._getFormattedDate(this.i18n.formatDate, date) : '';
888
966
  }
889
967
 
890
968
  /** @private */
@@ -957,7 +1035,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
957
1035
  }
958
1036
  this.close();
959
1037
  } else {
960
- if (!isValidDate && this._inputElement.value !== '') {
1038
+ if (!isValidDate && this._inputElementValue !== '') {
961
1039
  this.validate();
962
1040
  } else {
963
1041
  const oldValue = this.value;
@@ -975,7 +1053,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
975
1053
  this._close();
976
1054
  } else if (this.autoOpenDisabled) {
977
1055
  // Do not restore selected date if Esc was pressed after clearing input field
978
- if (this._inputElement.value === '') {
1056
+ if (this._inputElementValue === '') {
979
1057
  this._selectedDate = null;
980
1058
  }
981
1059
  this._applyInputValue(this._selectedDate);
@@ -1002,16 +1080,50 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
1002
1080
  }
1003
1081
 
1004
1082
  /** @private */
1005
- _getParsedDate(inputValue = this._inputValue) {
1083
+ _getParsedDate(inputValue = this._inputElementValue) {
1006
1084
  const dateObject = this.i18n.parseDate && this.i18n.parseDate(inputValue);
1007
1085
  const parsedDate = dateObject &&
1008
1086
  this._parseDate(dateObject.year + '-' + (dateObject.month + 1) + '-' + dateObject.day);
1009
1087
  return parsedDate;
1010
1088
  }
1011
1089
 
1090
+ /**
1091
+ * Sets the `_hasInputValue` property based on the `input` event.
1092
+ *
1093
+ * @param {InputEvent} event
1094
+ * @protected
1095
+ */
1096
+ _setHasInputValue(event) {
1097
+ const target = event.composedPath()[0];
1098
+ this._hasInputValue = target.value.length > 0;
1099
+ }
1100
+
1101
+ /**
1102
+ * An input event listener used to update `_hasInputValue` property.
1103
+ * Do not override this method.
1104
+ *
1105
+ * @param {Event} event
1106
+ * @private
1107
+ */
1108
+ __onUserInput(event) {
1109
+ this._setHasInputValue(event);
1110
+ this._onUserInput(event);
1111
+ }
1112
+
1113
+ /**
1114
+ * Observer to notify about the change of private property.
1115
+ *
1116
+ * @private
1117
+ */
1118
+ _hasInputValueChanged(hasValue, oldHasValue) {
1119
+ if (hasValue || oldHasValue) {
1120
+ this.dispatchEvent(new CustomEvent('has-input-value-changed'));
1121
+ }
1122
+ }
1123
+
1012
1124
  /** @private */
1013
1125
  _onUserInput(e) {
1014
- if (!this.opened && this._inputElement.value && !this.autoOpenDisabled) {
1126
+ if (!this.opened && this._inputElementValue && !this.autoOpenDisabled) {
1015
1127
  this.open();
1016
1128
  }
1017
1129
  this._userInputValueChanged();
@@ -1026,7 +1138,7 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
1026
1138
 
1027
1139
  /** @private */
1028
1140
  _userInputValueChanged(value) {
1029
- if (this._inputValue) {
1141
+ if (this._inputElementValue) {
1030
1142
  const parsedDate = this._getParsedDate();
1031
1143
 
1032
1144
  if (this._isValidDate(parsedDate)) {
@@ -1055,4 +1167,12 @@ export const DatePickerMixin = subclass => class VaadinDatePickerMixin extends m
1055
1167
  *
1056
1168
  * @event change
1057
1169
  */
1170
+
1171
+ /**
1172
+ * Fired whenever the field is validated.
1173
+ *
1174
+ * @event validated
1175
+ * @param {Object} detail
1176
+ * @param {boolean} detail.valid the result of the validation.
1177
+ */
1058
1178
  };
@@ -115,7 +115,6 @@ declare class DatePickerElement extends
115
115
  * Set to true to disable this element.
116
116
  */
117
117
  disabled: boolean;
118
- _inputValue: string;
119
118
 
120
119
  /**
121
120
  * Set to true to display the clear icon which clears the input.
@@ -147,7 +147,7 @@ class DatePickerElement extends
147
147
  }
148
148
 
149
149
  static get version() {
150
- return '4.5.0';
150
+ return '4.6.0';
151
151
  }
152
152
 
153
153
  static get properties() {
@@ -235,7 +235,7 @@ class DatePickerElement extends
235
235
  this._inputElement.addEventListener('change', (e) => {
236
236
  // For change event on text-field blur, after the field is cleared,
237
237
  // we schedule change event to be dispatched on date-picker blur.
238
- if (this._inputElement.value === '' && !e.__fromClearButton) {
238
+ if (this._inputElementValue === '' && !e.__fromClearButton) {
239
239
  this.__dispatchChange = true;
240
240
  }
241
241
  });
@@ -267,15 +267,6 @@ class DatePickerElement extends
267
267
  return this.$.input;
268
268
  }
269
269
 
270
- set _inputValue(value) {
271
- this._inputElement.value = value;
272
- }
273
-
274
- /** @return {string} */
275
- get _inputValue() {
276
- return this._inputElement.value;
277
- }
278
-
279
270
  /** @private */
280
271
  _getAriaExpanded(opened) {
281
272
  return Boolean(opened).toString();