Skip to content

Commit

Permalink
feat: add unparsable-change event (#6604)
Browse files Browse the repository at this point in the history
  • Loading branch information
vursen authored Oct 12, 2023
1 parent 677d037 commit 55cd888
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 63 deletions.
16 changes: 16 additions & 0 deletions packages/time-picker/src/vaadin-time-picker.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,22 @@ export interface TimePickerEventMap extends HTMLElementEventMap, TimePickerCusto
*
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
*
* ### Change events
*
* Depending on the nature of the value change that the user attempts to commit e.g. by pressing Enter,
* the component can fire either a `change` event or an `unparsable-change` event:
*
* Value change | Event
* :------------------------|:------------------
* empty => parsable | change
* empty => unparsable | unparsable-change
* parsable => empty | change
* parsable => parsable | change
* parsable => unparsable | change
* unparsable => empty | unparsable-change
* unparsable => parsable | change
* unparsable => unparsable | unparsable-change
*
* @fires {Event} change - Fired when the user commits a value change.
* @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
Expand Down
106 changes: 84 additions & 22 deletions packages/time-picker/src/vaadin-time-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ registerStyles('vaadin-time-picker', inputFieldShared, { moduleId: 'vaadin-time-
*
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
*
* ### Change events
*
* Depending on the nature of the value change that the user attempts to commit e.g. by pressing Enter,
* the component can fire either a `change` event or an `unparsable-change` event:
*
* Value change | Event
* :------------------------|:------------------
* empty => parsable | change
* empty => unparsable | unparsable-change
* parsable => empty | change
* parsable => parsable | change
* parsable => unparsable | change
* unparsable => empty | unparsable-change
* unparsable => parsable | change
* unparsable => unparsable | unparsable-change
*
* @fires {Event} change - Fired when the user commits a value change.
* @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
Expand Down Expand Up @@ -127,7 +143,6 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
position-target="[[_inputContainer]]"
theme$="[[_theme]]"
on-change="__onComboBoxChange"
on-validated="__onComboBoxValidated"
on-has-input-value-changed="__onComboBoxHasInputValueChanged"
>
<vaadin-input-container
Expand Down Expand Up @@ -356,6 +371,20 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
return this.$.clearButton;
}

/**
* The input element's value when it cannot be parsed as a time, and an empty string otherwise.
*
* @private
* @return {string}
*/
get __unparsableValue() {
if (this._inputElementValue && !this.i18n.parseTime(this._inputElementValue)) {
return this._inputElementValue;
}

return '';
}

/** @protected */
ready() {
super.ready();
Expand Down Expand Up @@ -421,6 +450,25 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
);
}

/**
* @param {boolean} focused
* @override
* @protected
*/
_setFocused(focused) {
super._setFocused(focused);

if (!focused) {
this.__commitValueChange();

// Do not validate when focusout is caused by document
// losing focus, which happens on browser tab switch.
if (document.hasFocus()) {
this.validate();
}
}
}

/** @private */
__validDayDivisor(step) {
// Valid if undefined, or exact divides a day, or has millisecond resolution
Expand Down Expand Up @@ -471,21 +519,39 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
this._comboBoxValue = this.i18n.formatTime(objWithStep);
this.__useMemo = false;

this.validate();
this.__commitPendingValue();
this.__commitValueChange();
}

/** @private */
__commitPendingValue() {
/**
* Depending on the nature of the value change that has occurred since
* the last commit attempt, triggers validation and fires an event:
*
* Value change | Event
* -------------------------|-------------------
* empty => parsable | change
* empty => unparsable | unparsable-change
* parsable => empty | change
* parsable => parsable | change
* parsable => unparsable | change
* unparsable => empty | unparsable-change
* unparsable => parsable | change
* unparsable => unparsable | unparsable-change
*
* @private
*/
__commitValueChange() {
const unparsableValue = this.__unparsableValue;

if (this.__committedValue !== this.value) {
this.__dispatchChange();
this.__committedValue = this.value;
this.validate();
this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
} else if (this.__committedUnparsableValue !== unparsableValue) {
this.validate();
this.dispatchEvent(new CustomEvent('unparsable-change'));
}
}

/** @private */
__dispatchChange() {
this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
this.__committedValue = this.value;
this.__committedUnparsableValue = unparsableValue;
}

/**
Expand Down Expand Up @@ -602,8 +668,9 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix

// Mark value set programmatically by the user
// as committed for the change event detection.
if (!this.__skipCommittedValueUpdate) {
if (!this.__keepCommittedValue) {
this.__committedValue = value;
this.__committedUnparsableValue = '';
}

if (value !== '' && value !== null && !parsedObj) {
Expand Down Expand Up @@ -636,9 +703,9 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
if (value !== newValue) {
this._comboBoxValue = newValue;
} else {
this.__skipCommittedValueUpdate = true;
this.__keepCommittedValue = true;
this.__updateValue(parsedObj);
this.__skipCommittedValueUpdate = false;
this.__keepCommittedValue = false;
}
} else {
// If the user input can not be parsed, set a flag
Expand All @@ -648,16 +715,16 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
this.__keepInvalidInput = true;
}

this.__skipCommittedValueUpdate = true;
this.__keepCommittedValue = true;
this.value = '';
this.__skipCommittedValueUpdate = false;
this.__keepCommittedValue = false;
}
}

/** @private */
__onComboBoxChange(event) {
event.stopPropagation();
this.__commitPendingValue();
this.__commitValueChange();
}

/**
Expand All @@ -669,11 +736,6 @@ class TimePicker extends PatternMixin(InputControlMixin(ThemableMixin(ElementMix
this._hasInputValue = this.$.comboBox._hasInputValue;
}

/** @private */
__onComboBoxValidated() {
this.validate();
}

/** @private */
__updateValue(obj) {
const timeString = this.__formatISO(this.__validateTime(obj)) || '';
Expand Down
Loading

0 comments on commit 55cd888

Please sign in to comment.