From 4a97ec3bd21a3eb3fc4505b5552b4c375b2cfee8 Mon Sep 17 00:00:00 2001 From: Nikolay Hristov Date: Mon, 18 Jan 2021 16:28:54 +0200 Subject: [PATCH 01/11] Iinitial --- packages/main/bundle.esm.js | 1 + packages/main/src/StepInput.hbs | 62 +++ packages/main/src/StepInput.js | 422 ++++++++++++++++++ .../main/src/i18n/messagebundle.properties | 6 + packages/main/src/themes/Input.css | 8 + packages/main/src/themes/StepInput.css | 123 +++++ packages/main/test/pages/StepInput.html | 184 ++++++++ 7 files changed, 806 insertions(+) create mode 100644 packages/main/src/StepInput.hbs create mode 100644 packages/main/src/StepInput.js create mode 100644 packages/main/src/themes/StepInput.css create mode 100644 packages/main/test/pages/StepInput.html diff --git a/packages/main/bundle.esm.js b/packages/main/bundle.esm.js index daa293de2cc5..7faaeed8f449 100644 --- a/packages/main/bundle.esm.js +++ b/packages/main/bundle.esm.js @@ -66,6 +66,7 @@ import ResponsivePopover from "./dist/ResponsivePopover.js"; import SegmentedButton from "./dist/SegmentedButton.js"; import Select from "./dist/Select.js"; import Slider from "./dist/Slider.js"; +import StepInput from "./dist/StepInput.js"; import RangeSlider from "./dist/RangeSlider.js"; import Switch from "./dist/Switch.js"; import MessageStrip from "./dist/MessageStrip.js"; diff --git a/packages/main/src/StepInput.hbs b/packages/main/src/StepInput.hbs new file mode 100644 index 000000000000..373c6cd5d5c7 --- /dev/null +++ b/packages/main/src/StepInput.hbs @@ -0,0 +1,62 @@ +
+
+ +
+ + + + + + +
+ +
+ + + +
diff --git a/packages/main/src/StepInput.js b/packages/main/src/StepInput.js new file mode 100644 index 000000000000..e2fb5510bfa4 --- /dev/null +++ b/packages/main/src/StepInput.js @@ -0,0 +1,422 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import StepInputTemplate from "./generated/templates/StepInputTemplate.lit.js"; +import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; +import Float from "@ui5/webcomponents-base/dist/types/Float.js"; +import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { STEPINPUT_DEC_ICON_TITLE, STEPINPUT_INC_ICON_TITLE } from "./generated/i18n/i18n-defaults.js"; +import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js"; +import { + isUp, + isDown, + isPageUp, + isPageDown, + isPageUpShift, + isPageDownShift, + isPageUpShiftCtrl, + isPageDownShiftCtrl, + isShow, + isF4, +} from "@ui5/webcomponents-base/dist/Keys.js"; +import "@ui5/webcomponents-icons/dist/less.js"; +import "@ui5/webcomponents-icons/dist/add.js"; + +import Icon from "./Icon.js"; +import Input from "./Input.js"; +import InputType from "./types/InputType.js"; + + +// Styles +import StepInputCss from "./generated/themes/StepInput.css.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-step-input", + properties: /** @lends sap.ui.webcomponents.main.StepInput.prototype */ { + /** + * Defines a value of the ui5-step-input. + * + * @type {Float} + * @defaultvalue 0 + * @public + */ + value: { + type: Float, + defaultValue: 0, + }, + + /** + * Defines a minimum value of the ui5-step-input. + * + * @type {Float} + * @public + */ + min: { + type: Float, + }, + + /** + * Defines a maximum value of the ui5-step-input. + * + * @type {Float} + * @public + */ + max: { + type: Float, + }, + + /** + * Defines a step of increasing/decreasing the value of the ui5-step-input. + * + * @type {Float} + * @defaultvalue 1 + * @public + */ + step: { + type: Float, + defaultValue: 1, + }, + + /** + * Defines the value state of the ui5-step-input. + *

+ * Available options are: + * + * + * @type {ValueState} + * @defaultvalue "None" + * @public + */ + valueState: { + type: ValueState, + defaultValue: ValueState.None, + }, + + /** + * Defines whether the ui5-step-input is required. + * + * @since 1.0.0-rc.9 + * @type {Boolean} + * @defaultvalue false + * @public + */ + required: { + type: Boolean, + }, + + /** + * Determines whether the ui5-step-input is displayed as disabled. + * + * @type {boolean} + * @defaultvalue false + * @public + */ + disabled: { + type: Boolean, + }, + + /** + * Determines whether the ui5-step-input is displayed as read-only. + * + * @type {boolean} + * @defaultvalue false + * @public + */ + readonly: { + type: Boolean, + }, + + /** + * Defines a short hint, intended to aid the user with data entry when the + * ui5-step-input has no value. + * + *

+ * Note: When no placeholder is set, the format pattern is displayed as a placeholder. + * Passing an empty string as the value of this property will make the ui5-step-input appear empty - without placeholder or format pattern. + * + * @type {string} + * @defaultvalue undefined + * @public + */ + placeholder: { + type: String, + defaultValue: undefined, + }, + + /** + * Determines the name with which the ui5-step-input will be submitted in an HTML form. + * + *

+ * Important: For the name property to have effect, you must add the following import to your project: + * import "@ui5/webcomponents/dist/features/InputElementsFormSupport.js"; + * + *

+ * Note: When set, a native input HTML element + * will be created inside the ui5-step-input so that it can be submitted as + * part of an HTML form. Do not use this property unless you need to submit a form. + * + * @type {string} + * @defaultvalue "" + * @public + */ + name: { + type: String, + }, + + /** + * Determines the text alignment of the ui5-step-input. + * + * @defaultvalue "left" + * @public + */ + align: { + type: String, + defaultValue: "left", + }, + + /** + * Defines the aria-label attribute for the ui5-step-input. + * + * @type {String} + * @since 1.0.0-rc.9 + * @private + * @defaultvalue "" + */ + ariaLabel: { + type: String, + }, + + /** + * Receives id(or many ids) of the elements that label the ui5-step-input. + * + * @type {String} + * @defaultvalue "" + * @private + * @since 1.0.0-rc.9 + */ + ariaLabelledby: { + type: String, + defaultValue: "", + }, + + _decIconDisabled: { + type: Boolean, + }, + + _incIconDisabled: { + type: Boolean, + }, + + }, + slots: /** @lends sap.ui.webcomponents.main.StepInput.prototype */ { + /** + * Defines the value state message that will be displayed as pop up under the ui5-step-input. + *

+ * + * Note: If not specified, a default text (in the respective language) will be displayed. + *
+ * Note: The valueStateMessage would be displayed, + * when the ui5-step-input is in Information, Warning or Error value state. + * @type {HTMLElement} + * @since 1.0.0-rc.7 + * @slot + * @public + */ + valueStateMessage: { + type: HTMLElement, + }, + }, + events: /** @lends sap.ui.webcomponents.main.StepInput.prototype */ { + /** + * Fired when the input operation has finished by pressing Enter or on focusout. + * + * @event + * @public + */ + change: {}, + }, +}; + +/** + * @class + * + *

Overview

+ * + * + *

Usage

+ * + * For the ui5-step-input + *

ES6 Module Import

+ * + * import @ui5/webcomponents/dist/StepInput.js"; + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.main.StepInput + * @extends UI5Element + * @tagname ui5-step-input + * @public + */ +class StepInput extends UI5Element { + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + constructor() { + super(); + this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + } + + static get styles() { + return StepInputCss; + } + + static get template() { + return StepInputTemplate; + } + + static get dependencies() { + return []; + } + + static async onDefine() { + await Promise.resolve([ + fetchI18nBundle("@ui5/webcomponents"), + ]); + } + + get decIconTitle() { + return this.i18nBundle.getText(STEPINPUT_DEC_ICON_TITLE); + } + + get decIconName() { + return "less"; + } + + get incIconTitle() { + return this.i18nBundle.getText(STEPINPUT_INC_ICON_TITLE); + } + + get incIconName() { + return "add"; + } + + get type() { + return InputType.Number; + } + + get _placeholder() { + return this.placeholder + " "; + } + + get _decIconInteractive() { + return !this._decIconDisabled; + } + + get _incIconInteractive() { + return !this._incIconDisabled; + } + + _onfocusin() { + this._getInputOuter().setAttribute("focused", ""); + } + + _onfocusout() { + this._getInputOuter().removeAttribute("focused"); + } + + _getInput() { + return this.shadowRoot.querySelector("[ui5-input]"); + } + + _getInputOuter() { + return this.shadowRoot.querySelector(".ui5-step-input-input"); + } + + _validate() { + if (!isNaN(this.min) && this.value < this.min) { + this.valueState = ValueState.Error; + this._decIconDisabled = true; + } else if (!isNaN(this.max) && this.value > this.max) { + this.valueState = ValueState.Error; + this._incIconDisabled = true; + } else { + this.valueState = ValueState.None; + this._decIconDisabled = false; + this._incIconDisabled = false; + } + } + + _modifyValue(modifier, fireChangeEvent) { + this.value = this.value + modifier; + this._validate(); + this._getInput().value = this.value; + this._getInputOuter().setAttribute("focused", ""); + if (fireChangeEvent) { + this.fireEvent('change', { value: this.value }); + } + } + + _incValue() { + if (!this.disabled && !this.readonly) { + this._modifyValue(this.step, true); + } + } + + _decValue() { + if (!this.disabled && !this.readonly) { + this._modifyValue(-this.step, true); + } + } + + /** + * The ui5-input "submit" event handler - fire change event when the user presses enter + * @protected + */ + _onInputSubmit(event) {} + + /** + * The ui5-input "change" event handler - fire change event when the user focuses out of the input + * @protected + */ + _onInputChange(event) { + //this._updateValueAndFireEvents(event.target.value, true, ["change", "value-changed"]); + } + + _onkeydown(event) { + if (this.disabled || this.readonly) { + return; + } + + if (isUp(event)) { + this._modifyValue(this.step); + } else if (isDown(event)) { + this._modifyValue(-this.step); + } + } + + + static get dependencies() { + return [ + Icon, + Input, + ]; + } + +} + +StepInput.define(); + +export default StepInput; diff --git a/packages/main/src/i18n/messagebundle.properties b/packages/main/src/i18n/messagebundle.properties index 3cb7c9448004..a204ba5d113e 100644 --- a/packages/main/src/i18n/messagebundle.properties +++ b/packages/main/src/i18n/messagebundle.properties @@ -228,3 +228,9 @@ DAY_PICKER_NON_WORKING_DAY = Non-Working Day #XBUT: Text for 'Today' in the DayPicker DAY_PICKER_TODAY = Today + +#XTOL: tooltip for decrease button of the StepInput +STEPINPUT_DEC_ICON_TITLE=Decrease + +#XTOL: tooltip for increase button of the StepInput +STEPINPUT_INC_ICON_TITLE=Increase diff --git a/packages/main/src/themes/Input.css b/packages/main/src/themes/Input.css index 008cc0cfe1de..350db80e735b 100644 --- a/packages/main/src/themes/Input.css +++ b/packages/main/src/themes/Input.css @@ -67,6 +67,7 @@ line-height: inherit; letter-spacing: inherit; word-spacing: inherit; + text-align: inherit; } [inner-input][inner-input-with-icon] { @@ -203,3 +204,10 @@ ::slotted([ui5-icon][slot="icon"]) { padding: var(--_ui5_input_icon_padding); } + +/* Chrome, Safari, Edge, Opera */ +[inner-input]::-webkit-outer-spin-button, +[inner-input]::-webkit-inner-spin-button { + -webkit-appearance: inherit; + margin: inherit; +} diff --git a/packages/main/src/themes/StepInput.css b/packages/main/src/themes/StepInput.css new file mode 100644 index 000000000000..757156e006c3 --- /dev/null +++ b/packages/main/src/themes/StepInput.css @@ -0,0 +1,123 @@ +@import "./InvisibleTextStyles.css"; +@import "./InputIcon.css"; + +:host(:not([hidden])) { + display: inline-block; +} + +:host { + color: var(--sapField_TextColor); + background-color: var(--sapField_Background); + border: 1px solid var(--sapField_BorderColor); + border-radius: var(--_ui5_input_wrapper_border_radius); + box-sizing: border-box; + height: var(--_ui5_input_height); + position: relative; +} + +:host(:not([value-state]):not([readonly]):hover), +:host([value-state=None]:not([readonly]):hover) { + background-color: var(--sapField_Hover_Background); + border: 1px solid var(--sapField_Hover_BorderColor); +} + +:host([value-state=Error]:not([readonly]):not([disabled]))::after, +:host([value-state=Information]:not([readonly]):not([disabled]))::after, +:host([value-state=Warning]:not([readonly]):not([disabled]))::after { + position: absolute; + content: ""; + top: -1px; + right: -1px; + bottom: -1px; + left: -1px; + outline: none; + pointer-events: none; + border-radius: var(--_ui5_input_wrapper_border_radius); + border-style: var(--_ui5_input_error_warning_border_style); + z-index: 2; +} + +:host([value-state=Error]:not([readonly]))::after { + border-color: var(--sapField_InvalidColor); +} + +:host([value-state]:not([value-state=None]))::after { + border-width: var(--_ui5_input_state_border_width); +} + +:host([value-state=Error]:not([readonly])) .ui5-step-input-input { + background-color: var(--sapField_InvalidBackground); +} + +:host .ui5-step-input-input { + width: auto; + min-width: inherit; + color: inherit; + background-color: inherit; + border: 1px solid transparent; + box-sizing: border-box; + vertical-align: top; + margin-top: -1px; + min-width: 8rem; + position: relative; + padding: 0px 2.5rem; +} + +:host .ui5-step-input-input[text-align=left] { + text-align: left; +} + +:host .ui5-step-input-input[text-align=center] { + text-align: center; +} + +:host .ui5-step-input-input[text-align=right] { + text-align: right; +} + +:host .ui5-step-icon { + position: absolute; + display: inline-block; + height: 2rem; + z-index: 1; +} + +:host .ui5-step-icon.ui5-step-dec { + left: 0; +} + +:host .ui5-step-icon.ui5-step-inc { + right: 0; +} + +:host .ui5-step-input-input[focused] { + outline: none; +} + +:host .ui5-step-input-input[focused]::after { + position: absolute; + content: ""; + border: var(--_ui5_input_focus_border_width) dotted var(--sapContent_FocusColor); + top: 0.0625rem; + right: 0; + bottom: 0.0625rem; + left: 0; + outline: none; + pointer-events: none; + z-index: 2; +} + +:host([value-state=Error]:not([readonly])) .ui5-step-input-input[focused]::after { + top: 0.125rem; + right: 0.0625rem; + bottom: 0.125rem; + left: 0.0625rem; +} + + +/* Chrome, Safari, Edge, Opera */ +:host .ui5-step-input-input::-webkit-outer-spin-button, +:host .ui5-step-input-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} diff --git a/packages/main/test/pages/StepInput.html b/packages/main/test/pages/StepInput.html new file mode 100644 index 000000000000..e872166e3a55 --- /dev/null +++ b/packages/main/test/pages/StepInput.html @@ -0,0 +1,184 @@ + + + + + + + StepInput test page + + + + + + + + + + + + + + +
+ + + + + + + From e37d3d6792b9d8e6eef6a268fdad164d71e13cb9 Mon Sep 17 00:00:00 2001 From: Nikolay Hristov Date: Fri, 22 Jan 2021 11:18:09 +0200 Subject: [PATCH 02/11] feat(ui5-stepinput): Inintial implementation --- packages/base/src/Keys.js | 12 ++ packages/main/src/StepInput.hbs | 18 ++- packages/main/src/StepInput.js | 187 ++++++++++++++++++------ packages/main/src/themes/StepInput.css | 26 +++- packages/main/test/pages/StepInput.html | 9 +- 5 files changed, 190 insertions(+), 62 deletions(-) diff --git a/packages/base/src/Keys.js b/packages/base/src/Keys.js index 25c3ae34c602..52a30be9c0b5 100644 --- a/packages/base/src/Keys.js +++ b/packages/base/src/Keys.js @@ -127,6 +127,14 @@ const isUpCtrl = event => (event.key ? (event.key === "ArrowUp" || event.key === const isDownCtrl = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, false, false); +const isUpShift = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_UP) && checkModifierKeys(event, false, false, true); + +const isDownShift = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, false, false, true); + +const isUpShiftCtrl = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_UP) && checkModifierKeys(event, true, false, true); + +const isDownShiftCtrl = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, false, true); + const isHome = event => (event.key ? event.key === "Home" : event.keyCode === KeyCodes.HOME) && !hasModifierKeys(event); const isEnd = event => (event.key ? event.key === "End" : event.keyCode === KeyCodes.END) && !hasModifierKeys(event); @@ -198,6 +206,10 @@ export { isRightCtrl, isUpCtrl, isDownCtrl, + isUpShift, + isDownShift, + isUpShiftCtrl, + isDownShiftCtrl, isHome, isEnd, isPlus, diff --git a/packages/main/src/StepInput.hbs b/packages/main/src/StepInput.hbs index 373c6cd5d5c7..02eccf4adde4 100644 --- a/packages/main/src/StepInput.hbs +++ b/packages/main/src/StepInput.hbs @@ -5,11 +5,11 @@ @keydown="{{_onkeydown}}" @focusin="{{_onfocusin}}" @focusout="{{_onfocusout}}" - >
@@ -28,23 +29,24 @@ class="ui5-step-input-input" placeholder="{{_placeholder}}" type="{{type}}" - value="{{value}}" + value="{{_valuePrecisioned}}" ?disabled="{{disabled}}" ?required="{{required}}" ?readonly="{{readonly}}" value-state="{{valueState}}" data-sap-focus-ref - text-align="{{align}}" + text-align="{{textAlign}}" ._inputAccInfo ="{{accInfo}}" @ui5-change="{{_onInputChange}}" - @ui5-submit="{{_onInputSubmit}}" + @ui5-submit="{{_onInputChange}}" + @focusout="{{_onInputChange}}" > -
diff --git a/packages/main/src/StepInput.js b/packages/main/src/StepInput.js index e2fb5510bfa4..f8d68c0a4735 100644 --- a/packages/main/src/StepInput.js +++ b/packages/main/src/StepInput.js @@ -3,20 +3,22 @@ import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import StepInputTemplate from "./generated/templates/StepInputTemplate.lit.js"; import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; import Float from "@ui5/webcomponents-base/dist/types/Float.js"; +import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import { STEPINPUT_DEC_ICON_TITLE, STEPINPUT_INC_ICON_TITLE } from "./generated/i18n/i18n-defaults.js"; import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js"; import { isUp, isDown, - isPageUp, - isPageDown, + isUpCtrl, + isDownCtrl, + isUpShift, + isDownShift, + isUpShiftCtrl, + isDownShiftCtrl, isPageUpShift, isPageDownShift, - isPageUpShiftCtrl, - isPageDownShiftCtrl, - isShow, - isF4, + isEscape, } from "@ui5/webcomponents-base/dist/Keys.js"; import "@ui5/webcomponents-icons/dist/less.js"; import "@ui5/webcomponents-icons/dist/add.js"; @@ -174,14 +176,27 @@ const metadata = { /** * Determines the text alignment of the ui5-step-input. * - * @defaultvalue "left" - * @public - */ - align: { + * @type {string} + * @defaultvalue "left" + * @public + */ + textAlign: { type: String, defaultValue: "left", }, + /** + * Determines the number of digits after the decimal point of the ui5-step-input. + * + * @type {Integer} + * @defaultvalue 0 + * @public + */ + valuePrecision: { + type: Integer, + defaultValue: 0, + }, + /** * Defines the aria-label attribute for the ui5-step-input. * @@ -215,6 +230,14 @@ const metadata = { type: Boolean, }, + _focused: { + type: Boolean, + }, + + _previousValue: { + type: Float, + } + }, slots: /** @lends sap.ui.webcomponents.main.StepInput.prototype */ { /** @@ -322,19 +345,23 @@ class StepInput extends UI5Element { } get _decIconInteractive() { - return !this._decIconDisabled; + return !this._decIconDisabled && !this.readonly && !this.disabled; } get _incIconInteractive() { - return !this._incIconDisabled; + return !this._incIconDisabled && !this.readonly && !this.disabled; } - _onfocusin() { - this._getInputOuter().setAttribute("focused", ""); + get _isFocused() { + return this._focused; } - _onfocusout() { - this._getInputOuter().removeAttribute("focused"); + get _disableFocus() { + return false; + } + + get _valuePrecisioned() { + return this.value.toFixed(this.valuePrecision); } _getInput() { @@ -345,65 +372,139 @@ class StepInput extends UI5Element { return this.shadowRoot.querySelector(".ui5-step-input-input"); } + _buttonsState() { + this._decIconDisabled = !isNaN(this.min) && this.value <= this.min ? true : false; + this._incIconDisabled = !isNaN(this.max) && this.value >= this.max ? true : false; + } + _validate() { - if (!isNaN(this.min) && this.value < this.min) { - this.valueState = ValueState.Error; - this._decIconDisabled = true; - } else if (!isNaN(this.max) && this.value > this.max) { - this.valueState = ValueState.Error; - this._incIconDisabled = true; - } else { - this.valueState = ValueState.None; - this._decIconDisabled = false; - this._incIconDisabled = false; - } + this.valueState = ( (!isNaN(this.min) && this.value < this.min) || + (!isNaN(this.max) && this.value > this.max)) ? + ValueState.Error : ValueState.None; + } + + _preciseValue(value) { + let pow = Math.pow(10, this.valuePrecision); + return Math.round(value*pow)/pow; + } + + _fireChangeEvent() { + console.warn('Fire "change" event with value: ' + this.value); + this._previousValue = this.value; + this.fireEvent('change', { value: this.value }); } _modifyValue(modifier, fireChangeEvent) { - this.value = this.value + modifier; - this._validate(); - this._getInput().value = this.value; - this._getInputOuter().setAttribute("focused", ""); - if (fireChangeEvent) { - this.fireEvent('change', { value: this.value }); + let value; + this.value = this._preciseValue(parseFloat(this._getInput().value)); + value = this.value + modifier; // USE sumValues from UI5 StepInput here + if (!isNaN(this.min) && value < this.min) { + value = this.min; + } + if (!isNaN(this.max) && value > this.max) { + value = this.max; } + value = this._preciseValue(value); + if (value !== this.value) { + this.value = value; + this._validate(); + this._buttonsState(); + this._focused = true; + this._getInputOuter().setAttribute("focused", ""); + if (fireChangeEvent) { + this._fireChangeEvent(); + } else { + this._getInput().focus(); + } + } + } + + _spinValue() { } - _incValue() { - if (!this.disabled && !this.readonly) { + _incValue(event) { + if (this._incIconInteractive && event.isTrusted && !this.disabled && !this.readonly) { this._modifyValue(this.step, true); + this._previousValue = this.value; } } - _decValue() { - if (!this.disabled && !this.readonly) { + _decValue(event) { + if (this._decIconInteractive && event.isTrusted && !this.disabled && !this.readonly) { this._modifyValue(-this.step, true); + this._previousValue = this.value; } } - /** - * The ui5-input "submit" event handler - fire change event when the user presses enter - * @protected - */ - _onInputSubmit(event) {} + _valueMin() { + if (this.min !== undefined) { + return this.min; + } else { + false; + } + } /** * The ui5-input "change" event handler - fire change event when the user focuses out of the input * @protected */ _onInputChange(event) { - //this._updateValueAndFireEvents(event.target.value, true, ["change", "value-changed"]); + let inputValue = this._preciseValue(parseFloat(this._getInput().value)); + if (this.value !== this._previousValue || this.value !== inputValue) { + this.value = inputValue; + this._validate(); + this._buttonsState(); + this._fireChangeEvent(); + } + } + + _onmousedown() { + // need this in order to implement SPIN functionality + } + + _onmouseup() { + // need this in order to implement SPIN functionality + } + + _onfocusin() { + this._focused = true; + this._validate(); + this._buttonsState(); + } + + _onfocusout() { + this._focused = false; + this._validate(); + this._buttonsState(); } _onkeydown(event) { + let preventDefault = true; if (this.disabled || this.readonly) { return; } if (isUp(event)) { + // step up this._modifyValue(this.step); } else if (isDown(event)) { + // step down this._modifyValue(-this.step); + } else if (isEscape(event)) { + // return previous value + this.value = this._previousValue; + this._getInput().value = this.value.toFixed(this.valuePrecision); + } else if (!isNaN(this.max) && (isPageUpShift(event) || isUpShiftCtrl(event))) { + // step to max + this._modifyValue(this.max - this.value); + } else if (!isNaN(this.min) && (isPageDownShift(event) || isDownShiftCtrl(event))) { + //step to min + this._modifyValue(this.min - this.value); + } else if (!isUpCtrl(event) && !isDownCtrl(event) && !isUpShift(event) && !isDownShift(event)) { + preventDefault = false; + } + if (preventDefault) { + event.preventDefault(); } } diff --git a/packages/main/src/themes/StepInput.css b/packages/main/src/themes/StepInput.css index 757156e006c3..9bd23a00ab19 100644 --- a/packages/main/src/themes/StepInput.css +++ b/packages/main/src/themes/StepInput.css @@ -15,8 +15,8 @@ position: relative; } -:host(:not([value-state]):not([readonly]):hover), -:host([value-state=None]:not([readonly]):hover) { +:host(:not([value-state]):not([readonly]):not([disabled]):hover), +:host([value-state=None]:not([readonly]):not([disabled]):hover) { background-color: var(--sapField_Hover_Background); border: 1px solid var(--sapField_Hover_BorderColor); } @@ -37,7 +37,7 @@ z-index: 2; } -:host([value-state=Error]:not([readonly]))::after { +:host([value-state=Error]:not([readonly]):not([disabled]))::after { border-color: var(--sapField_InvalidColor); } @@ -45,7 +45,7 @@ border-width: var(--_ui5_input_state_border_width); } -:host([value-state=Error]:not([readonly])) .ui5-step-input-input { +:host([value-state=Error]:not([readonly]):not([disabled])) .ui5-step-input-input { background-color: var(--sapField_InvalidBackground); } @@ -82,6 +82,11 @@ z-index: 1; } +:host .ui5-step-icon[focused] { + border: none; + outline: none; +} + :host .ui5-step-icon.ui5-step-dec { left: 0; } @@ -90,8 +95,14 @@ right: 0; } -:host .ui5-step-input-input[focused] { - outline: none; +:host .ui5-step-icon:not([interactive]) { + opacity: 0.5; +} + +:host .ui5-step-icon:not([interactive]) *:hover, +:host .ui5-step-icon:not([interactive]) *:active { + background-color: var(--sapField_Background); + color: var(--sapContent_IconColor); } :host .ui5-step-input-input[focused]::after { @@ -107,14 +118,13 @@ z-index: 2; } -:host([value-state=Error]:not([readonly])) .ui5-step-input-input[focused]::after { +:host([value-state=Error]:not([readonly]):not([disabled])) .ui5-step-input-input[focused]::after { top: 0.125rem; right: 0.0625rem; bottom: 0.125rem; left: 0.0625rem; } - /* Chrome, Safari, Edge, Opera */ :host .ui5-step-input-input::-webkit-outer-spin-button, :host .ui5-step-input-input::-webkit-inner-spin-button { diff --git a/packages/main/test/pages/StepInput.html b/packages/main/test/pages/StepInput.html index e872166e3a55..fc5ea71fbffe 100644 --- a/packages/main/test/pages/StepInput.html +++ b/packages/main/test/pages/StepInput.html @@ -35,14 +35,15 @@ -
+
+ + +
From a2b369d45a4bfc63f6707f712ba9cd35d4b8831c Mon Sep 17 00:00:00 2001 From: Nikolay Hristov Date: Fri, 5 Feb 2021 12:29:04 +0200 Subject: [PATCH 04/11] Next --- packages/main/src/Input.hbs | 6 +- packages/main/src/Input.js | 21 ++- packages/main/src/StepInput.hbs | 21 ++- packages/main/src/StepInput.js | 241 +++++++++++++++++------- packages/main/src/themes/Input.css | 3 + packages/main/src/themes/StepInput.css | 104 ++++++++-- packages/main/test/pages/StepInput.html | 131 +++++++++++-- 7 files changed, 415 insertions(+), 112 deletions(-) diff --git a/packages/main/src/Input.hbs b/packages/main/src/Input.hbs index 03fe903607d9..48a9bd6b37ed 100644 --- a/packages/main/src/Input.hbs +++ b/packages/main/src/Input.hbs @@ -34,9 +34,9 @@ @focusin={{innerFocusIn}} data-sap-no-tab-ref data-sap-focus-ref - step="{{accInfo.input.step}}" - min="{{accInfo.input.min}}" - max="{{accInfo.input.max}}" + step="{{inputAttributes.input.step}}" + min="{{inputAttributes.input.min}}" + max="{{inputAttributes.input.max}}" /> {{#if icon.length}}
diff --git a/packages/main/src/Input.js b/packages/main/src/Input.js index 288381ac964b..08ce4d64f447 100644 --- a/packages/main/src/Input.js +++ b/packages/main/src/Input.js @@ -332,6 +332,14 @@ const metadata = { type: Object, }, + _wrapperAccInfo: { + type: Object, + }, + + _inputInnerAttributes: { + type: Object, + }, + _inputWidth: { type: Integer, }, @@ -1068,9 +1076,16 @@ class Input extends UI5Element { "ariaExpanded": this._inputAccInfo && this._inputAccInfo.ariaExpanded, "ariaDescription": this._inputAccInfo && this._inputAccInfo.ariaDescription, "ariaLabel": (this._inputAccInfo && this._inputAccInfo.ariaLabel) || getEffectiveAriaLabelText(this), - "min": this._inputAccInfo.min, - "max": this._inputAccInfo.max, - "step": this.type === InputType.Number ? (this._inputAccInfo.step || "any") : undefined, + }, + }; + } + + get inputAttributes() { + return { + "input": { + "min": this.type === InputType.Number ? this._inputInnerAttributes.min : undefined, + "max": this.type === InputType.Number ? this._inputInnerAttributes.max : undefined, + "step": this.type === InputType.Number ? (this._inputInnerAttributes.step || "any") : undefined, }, }; } diff --git a/packages/main/src/StepInput.hbs b/packages/main/src/StepInput.hbs index 4911bf46b4d8..d59a18d82939 100644 --- a/packages/main/src/StepInput.hbs +++ b/packages/main/src/StepInput.hbs @@ -6,21 +6,23 @@ @focusin="{{_onfocusin}}" @focusout="{{_onfocusout}}" > +
@@ -28,7 +30,7 @@ +
diff --git a/packages/main/src/StepInput.js b/packages/main/src/StepInput.js index 6b8f698d13da..1932b818aea0 100644 --- a/packages/main/src/StepInput.js +++ b/packages/main/src/StepInput.js @@ -105,7 +105,6 @@ const metadata = { /** * Defines whether the ui5-step-input is required. * - * @since 1.0.0-rc.9 * @type {Boolean} * @defaultvalue false * @public @@ -173,18 +172,6 @@ const metadata = { type: String, }, - /** - * Determines the text alignment of the ui5-step-input. - * - * @type {string} - * @defaultvalue "left" - * @public - */ - textAlign: { - type: String, - defaultValue: "left", - }, - /** * Determines the number of digits after the decimal point of the ui5-step-input. * @@ -201,7 +188,6 @@ const metadata = { * Defines the aria-label attribute for the ui5-step-input. * * @type {String} - * @since 1.0.0-rc.9 * @private * @defaultvalue "" */ @@ -215,7 +201,6 @@ const metadata = { * @type {String} * @defaultvalue "" * @private - * @since 1.0.0-rc.9 */ ariaLabelledby: { type: String, @@ -247,6 +232,38 @@ const metadata = { noAttribute: true, }, + _previousValueState: { + type: String, + noAttribute: true, + defaultValue: "", + }, + + _waitTimeout: { + type: Float, + noAttribute: true, + }, + + _speed: { + type: Float, + noAttribute: true, + }, + + _btnDown: { + type: Boolean, + noAttribute: true, + defaultValue: false, + }, + + _spinTimeoutId: { + type: Integer, + noAttribute: true, + }, + + _spinStarted: { + type: Boolean, + noAttribute: true, + defaultValue: false, + }, }, slots: /** @lends sap.ui.webcomponents.main.StepInput.prototype */ { /** @@ -258,7 +275,6 @@ const metadata = { * Note: The valueStateMessage would be displayed, * when the ui5-step-input is in Information, Warning or Error value state. * @type {HTMLElement} - * @since 1.0.0-rc.7 * @slot * @public */ @@ -282,9 +298,36 @@ const metadata = { * *

Overview

* + * The ui5-step-input consists of an input field and buttons with icons to increase/decrease the value + * with the predefined step. + * + * The user can change the value of the component by pressing the increase/decrease buttons, + * by typing a number directly, by using the keyboard up/down and page up/down, + * or by using the mouse scroll wheel. Decimal values are supported. * *

Usage

* + * The default step is 1 but the app developer can set a different one. + * + * App developers can set a maximum and minimum value for the StepInput. + * The increase/decrease button and the up/down keyboard navigation become disabled when + * the value reaches the max/min or a new value is entered from the input which is greater/less than the max/min. + * + * When to use + *
    + *
  • To adjust amounts, quantities, or other values quickly.
  • + *
  • To adjust values for a specific step.
  • + *
+ * + * When not to use + *
    + *
  • To enter a static number (for example, postal code, phone number, or ID). In this case, + * use the regular ui5-input instead.
  • + *
  • To display a value that rarely needs to be adjusted and does not pertain to a particular step. + * In this case, use the regular ui5-input instead.
  • + *
  • To enter dates and times. In this case, use date/time related components instead.
  • + *
+ * * For the ui5-step-input *

ES6 Module Import

* @@ -295,6 +338,7 @@ const metadata = { * @alias sap.ui.webcomponents.main.StepInput * @extends UI5Element * @tagname ui5-step-input + * @since 1.0.0-rc.12 * @public */ class StepInput extends UI5Element { @@ -302,6 +346,12 @@ class StepInput extends UI5Element { constructor() { super(); this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + + // spin variables + this.INITIAL_WAIT_TIMEOUT = 500; // milliseconds + this.ACCELERATION = 0.8; + this.MIN_WAIT_TIMEOUT = 50; // milliseconds + this.INITIAL_SPEED = 120; // milliseconds } static get metadata() { @@ -321,15 +371,22 @@ class StepInput extends UI5Element { } static get dependencies() { - return []; + return [ + Icon, + Input, + ]; } static async onDefine() { - await Promise.resolve([ - fetchI18nBundle("@ui5/webcomponents"), - ]); + await fetchI18nBundle("@ui5/webcomponents"); + } + + get type() { + return InputType.Number; } + // icons-related + get decIconTitle() { return this.i18nBundle.getText(STEPINPUT_DEC_ICON_TITLE); } @@ -346,19 +403,11 @@ class StepInput extends UI5Element { return "add"; } - get type() { - return InputType.Number; - } - - get _placeholder() { - return this.placeholder + " "; - } - - get _decIconInteractive() { + get _decIconClickable() { return !this._decIconDisabled && !this.readonly && !this.disabled; } - get _incIconInteractive() { + get _incIconClickable() { return !this._incIconDisabled && !this.readonly && !this.disabled; } @@ -366,15 +415,11 @@ class StepInput extends UI5Element { return this._focused; } - get _disableFocus() { - return false; - } - get _valuePrecisioned() { return this.value.toFixed(this.valuePrecision); } - get accInfo() { + get inputAttributes() { return { min: isNaN(this.min) ? undefined : this.min, max: isNaN(this.max) ? undefined : this.max, @@ -382,10 +427,22 @@ class StepInput extends UI5Element { }; } + onBeforeRendering() { + this._buttonsState(); + } + + get input() { + return this.shadowRoot.querySelector("[ui5-input]"); + } + + get inputOuter() { + return this.shadowRoot.querySelector(".ui5-step-input-input"); + } + _onButtonFocusOut() { setTimeout(function() { if (!this._inputFocused) { - this._getInputOuter().removeAttribute("focused"); + this.inputOuter.removeAttribute("focused"); } }.bind(this), 0); } @@ -399,23 +456,18 @@ class StepInput extends UI5Element { this._onInputChange(); } - _getInput() { - return this.shadowRoot.querySelector("[ui5-input]"); - } - - _getInputOuter() { - return this.shadowRoot.querySelector(".ui5-step-input-input"); - } - _buttonsState() { this._decIconDisabled = !isNaN(this.min) && this.value <= this.min ? true : false; this._incIconDisabled = !isNaN(this.max) && this.value >= this.max ? true : false; } _validate() { + if (this._previousValueState === "") { + this._previousValueState = this.valueState !== "" ? this.valueState : ValueState.None; + } this.valueState = ( (!isNaN(this.min) && this.value < this.min) || (!isNaN(this.max) && this.value > this.max)) ? - ValueState.Error : ValueState.None; + ValueState.Error : this._previousValueState; } _preciseValue(value) { @@ -424,14 +476,20 @@ class StepInput extends UI5Element { } _fireChangeEvent() { - console.warn('Fire "change" event with value: ' + this.value); this._previousValue = this.value; this.fireEvent('change', { value: this.value }); } + /** + * Value modifier - modifies the value of the component, validates the new value and enables/disables increment and + * decrement buttons according to the value and min/max values (if set). Fires change event when requested + * + * @param {Float} modifier modifies the value of the component with the given modifier (positive or negative) + * @param {Boolean} fireChangeEvent if true, fires change event when the value is changed + */ _modifyValue(modifier, fireChangeEvent) { let value; - this.value = this._preciseValue(parseFloat(this._getInput().value)); + this.value = this._preciseValue(parseFloat(this.input.value)); value = this.value + modifier; if (!isNaN(this.min) && value < this.min) { value = this.min; @@ -445,36 +503,32 @@ class StepInput extends UI5Element { this._validate(); this._buttonsState(); this._focused = true; - this._getInputOuter().setAttribute("focused", ""); + this.inputOuter.setAttribute("focused", ""); if (fireChangeEvent) { this._fireChangeEvent(); } else { - this._getInput().focus(); + this.input.focus(); } } } _incValue(event) { - if (this._incIconInteractive && event.isTrusted && !this.disabled && !this.readonly) { + if (this._incIconClickable && event.isTrusted && !this.disabled && !this.readonly) { this._modifyValue(this.step, true); this._previousValue = this.value; } } _decValue(event) { - if (this._decIconInteractive && event.isTrusted && !this.disabled && !this.readonly) { + if (this._decIconClickable && event.isTrusted && !this.disabled && !this.readonly) { this._modifyValue(-this.step, true); this._previousValue = this.value; } } - /** - * The ui5-input "change" event handler - fire change event when the user focuses out of the input - * @protected - */ _onInputChange(event) { - let inputValue = this._preciseValue(parseFloat(this._getInput().value)); - if (this.value !== this._previousValue || this.value !== inputValue) { + let inputValue = this._preciseValue(parseFloat(this.input.value)); + if ((!isNaN(this._previousValue) && this.value !== this._previousValue) || this.value !== inputValue) { this.value = inputValue; this._validate(); this._buttonsState(); @@ -484,12 +538,10 @@ class StepInput extends UI5Element { _onfocusin() { this._focused = true; - this._validate(); } _onfocusout() { this._focused = false; - this._validate(); } _onkeydown(event) { @@ -507,7 +559,7 @@ class StepInput extends UI5Element { } else if (isEscape(event)) { // return previous value this.value = this._previousValue; - this._getInput().value = this.value.toFixed(this.valuePrecision); + this.input.value = this.value.toFixed(this.valuePrecision); } else if (!isNaN(this.max) && (isPageUpShift(event) || isUpShiftCtrl(event))) { // step to max this._modifyValue(this.max - this.value); @@ -522,15 +574,70 @@ class StepInput extends UI5Element { } } - onBeforeRendering() { - this._buttonsState(); + _decSpin() { + if (!this._decIconDisabled) { + this._spinValue(false, true); + } } - static get dependencies() { - return [ - Icon, - Input, - ]; + _incSpin() { + if (!this._incIconDisabled) { + this._spinValue(true, true); + } + } + + /** + * Calculates the time which should be waited until _spinValue function is called. + */ + _calcWaitTimeout() { + this._speed *= this.ACCELERATION; + this._waitTimeout = ((this._waitTimeout - this._speed) < this.MIN_WAIT_TIMEOUT ? this.MIN_WAIT_TIMEOUT : (this._waitTimeout - this._speed)); + return this._waitTimeout; + } + + /** + * Called when the increment or decrement button is pressed and held to set new value. + * @param {boolean} increment - is this the increment button or not so the values should be spin accordingly up or down + * @param {boolean} resetVariables - whether to reset the spin-related variables or not + */ + _spinValue(increment, resetVariables) { + if (resetVariables) { + this._waitTimeout = this.INITIAL_WAIT_TIMEOUT; + this._speed = this.INITIAL_SPEED; + this._btnDown = true; + } + this._spinTimeoutId = setTimeout(function () { + if (this._btnDown) { + this._spinStarted = true; + this._modifyValue(increment ? this.step : -this.step); + this._buttonsState(); + if ((!this._incIconDisabled && increment) || (!this._decIconDisabled && !increment)) { + this._spinValue(increment); + } else { + this._resetSpin(); + this._fireChangeEvent(); + } + } + }.bind(this), this._calcWaitTimeout()); + } + + /** + * Resets spin process + */ + _resetSpin() { + clearTimeout(this._spinTimeoutId); + this._btnDown = false; + this._spinStarted = false; + } + + /** + * Resets spin process when mouse outs + or - buttons + */ + _resetSpinOut() { + if (this._btnDown) { + this._resetSpin(); + this._fireChangeEvent(); + } } } diff --git a/packages/main/src/themes/Input.css b/packages/main/src/themes/Input.css index 350db80e735b..e82ec0e1e425 100644 --- a/packages/main/src/themes/Input.css +++ b/packages/main/src/themes/Input.css @@ -89,6 +89,7 @@ [inner-input]::-webkit-input-placeholder { font-style: italic; color: var(--sapField_PlaceholderTextColor); + padding-right: 2px; } :host([disabled]) [inner-input]::-moz-placeholder { @@ -100,6 +101,7 @@ [inner-input]::-moz-placeholder { font-style: italic; color: var(--sapField_PlaceholderTextColor); + padding-right: 2px; } :host([disabled]) [inner-input]:-ms-input-placeholder { @@ -111,6 +113,7 @@ [inner-input]:-ms-input-placeholder { font-style: italic; color: var(--sapField_PlaceholderTextColor); + padding-right: 2px; } .ui5-input-content { diff --git a/packages/main/src/themes/StepInput.css b/packages/main/src/themes/StepInput.css index fc2b57677f57..c93aec6e3406 100644 --- a/packages/main/src/themes/StepInput.css +++ b/packages/main/src/themes/StepInput.css @@ -16,13 +16,19 @@ position: relative; } +:host .ui5-step-input-input { + text-align: inherit; +} + :host(:not([value-state]):not([readonly]):not([disabled]):hover), :host([value-state=None]:not([readonly]):not([disabled]):hover) { background-color: var(--sapField_Hover_Background); border: 1px solid var(--sapField_Hover_BorderColor); } +:host([value-state=Success]:not([readonly]):not([disabled]))::after, :host([value-state=Error]:not([readonly]):not([disabled]))::after, +:host([value-state=None]:not([readonly]):not([disabled]))::after, :host([value-state=Information]:not([readonly]):not([disabled]))::after, :host([value-state=Warning]:not([readonly]):not([disabled]))::after { position: absolute; @@ -35,14 +41,31 @@ pointer-events: none; border-radius: var(--_ui5_input_wrapper_border_radius); border-style: var(--_ui5_input_error_warning_border_style); - z-index: 2; + z-index: 3; + border-width: 0px; +} + +:host([value-state=Information]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_InformationColor); + border-width: var(--_ui5-input-information_border_width); +} + +:host([value-state=Warning]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_WarningColor); + border-width: 2px; +} + +:host([value-state=Success]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_SuccessColor); + border-width: 1px; } :host([value-state=Error]:not([readonly]):not([disabled]))::after { - border-color: var(--sapField_InvalidColor); + border-color: var(--sapField_InvalidColor); + border-width: var(--_ui5-input-information_border_width); } -:host([value-state]:not([value-state=None]))::after { +:host([value-state])::after { border-width: var(--_ui5_input_state_border_width); } @@ -50,9 +73,12 @@ background-color: var(--sapField_InvalidBackground); } +:host([value-state]:not([value-state="None"]) .ui5-step-input-input[focused]) { + outline: none; +} + :host .ui5-step-input-input { width: 100%; - min-width: 50%; color: inherit; background-color: inherit; border: 1px solid transparent; @@ -61,7 +87,8 @@ margin-top: -1px; min-width: 8rem; position: relative; - padding: 0px 2.5rem; + padding: 0px 2.5rem 0px 2.4375rem; + outline: none; } :host .ui5-step-input-input[text-align=left] { @@ -80,7 +107,9 @@ position: absolute; display: inline-block; height: 2rem; - z-index: 1; + height: 100%; + background-color: var(--sapField_Background); + z-index: 2; } :host .ui5-step-icon[focused] { @@ -96,12 +125,16 @@ right: 0; } -:host .ui5-step-icon:not([interactive]) { +:host .ui5-step-icon *:not([clickable]), +:host .ui5-step-icon *:not([clickable]):active, +:host .ui5-step-icon *:not([clickable]):hover { opacity: 0.5; + background-color: transparent; + color: var(--sapContent_IconColor); } -:host .ui5-step-icon:not([interactive]) *:hover, -:host .ui5-step-icon:not([interactive]) *:active { +:host .ui5-step-icon :not([clickable]) *:hover, +:host .ui5-step-icon :not([clickable]) *:active { background-color: var(--sapField_Background); color: var(--sapContent_IconColor); } @@ -111,24 +144,63 @@ content: ""; border: var(--_ui5_input_focus_border_width) dotted var(--sapContent_FocusColor); top: 1px; - right: 1px; + right: 0px; bottom: 1px; - left: 1px; + left: 0px; outline: none; pointer-events: none; - z-index: 2; + z-index: 3; } -:host([value-state=Error]:not([readonly]):not([disabled])) .ui5-step-input-input[focused]::after { +:host .ui5-step-input-input[focused] { + outline: none; +} + +:host([value-state]:not([value-state=None]):not([value-state=Success]):not([readonly]):not([disabled])) .ui5-step-input-input[focused]::after { top: 2px; - right: 2px; + right: 1px; bottom: 2px; - left: 2px; + left: 1px; +} + +:host([value-state=Information]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_InformationColor); + border-width: var(--_ui5-input-information_border_width); +} + +:host([value-state=Warning]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_WarningColor); +} + +:host([value-state=Success]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_SuccessColor); + border-width: 1px; +} + +:host([value-state=Error]:not([readonly]):not([disabled]))::after { + border-color: var(--sapField_InvalidColor); } -/* Chrome, Safari, Edge, Opera */ +/* Disable spin buttons in Chrome, Safari, Edge, Opera */ :host .ui5-step-input-input::-webkit-outer-spin-button, :host .ui5-step-input-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } + +:host([disabled]) { + opacity: var(--_ui5_input_disabled_opacity); + cursor: default; + pointer-events: none; + background: var(--sapField_ReadOnly_Background); + border-color: var(--sapField_ReadOnly_BorderColor); +} + +:host([disabled]) .ui5-step-icon { + background: var(--sapField_ReadOnly_Background); +} + +:host([disabled]) .ui5-step-icon [ui5-icon] { + color: var(--sapField_ReadOnly_BorderColor); +} + diff --git a/packages/main/test/pages/StepInput.html b/packages/main/test/pages/StepInput.html index 413cae42f8c3..02d29d6b39f2 100644 --- a/packages/main/test/pages/StepInput.html +++ b/packages/main/test/pages/StepInput.html @@ -32,36 +32,139 @@ .sapUiTheme-sap_fiori3 body { background: #f7f7f7; } + + h3 { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */ + } -
- StepInput + Event [change] :: N/A
+ +
+

StepInput in Cozy

+ +
+ +
+

StepInput in Compact

+ +
+ +
+

StepInput in with min=0, max=10 and step=1

+ - - + style="text-align: right; width: 250px" + />
-
- - +

StepInput in with min=0, max=10, step=0.05 and valuePrecision=2

+ - + style="text-align: center; width: 250px" + /> +
+ +
+

Disabled StepInput

+ +
+
+

Readonly StepInput

+ +
+ +
+

StepInput with valueState=None

+
+ +
+

StepInput with valueState=Success

+ +
+ +
+

StepInput with valueState=Information

+ +
+ +
+

StepInput with valueState=Warning

+ +
+ +
+

StepInput with valueState=Error

+ +
+ + + From 251ea06e955b33da6119bba823d3a00c3876cd18 Mon Sep 17 00:00:00 2001 From: Nikolay Hristov Date: Wed, 10 Feb 2021 08:57:05 +0200 Subject: [PATCH 05/11] feat(ui5-step-input): final + tests --- packages/main/src/StepInput.js | 8 +- packages/main/test/pages/StepInput.html | 42 +- packages/main/test/specs/StepInput.spec.js | 446 +++++++++++++++++++++ 3 files changed, 474 insertions(+), 22 deletions(-) create mode 100644 packages/main/test/specs/StepInput.spec.js diff --git a/packages/main/src/StepInput.js b/packages/main/src/StepInput.js index 1932b818aea0..3d2c33ed65ea 100644 --- a/packages/main/src/StepInput.js +++ b/packages/main/src/StepInput.js @@ -352,6 +352,10 @@ class StepInput extends UI5Element { this.ACCELERATION = 0.8; this.MIN_WAIT_TIMEOUT = 50; // milliseconds this.INITIAL_SPEED = 120; // milliseconds + + if (this._previousValue === undefined) { + this._previousValue = this.value; + } } static get metadata() { @@ -528,8 +532,8 @@ class StepInput extends UI5Element { _onInputChange(event) { let inputValue = this._preciseValue(parseFloat(this.input.value)); - if ((!isNaN(this._previousValue) && this.value !== this._previousValue) || this.value !== inputValue) { - this.value = inputValue; + if (this.value !== this._previousValue || this.value !== inputValue) { + this.value = inputValue; this._validate(); this._buttonsState(); this._fireChangeEvent(); diff --git a/packages/main/test/pages/StepInput.html b/packages/main/test/pages/StepInput.html index 02d29d6b39f2..5c89e0bea11d 100644 --- a/packages/main/test/pages/StepInput.html +++ b/packages/main/test/pages/StepInput.html @@ -14,11 +14,6 @@ - -