Skip to content

Commit 7b78c16

Browse files
authored
feat(ui5-slider): focus and keyboard handling implementation (#2614)
1 parent a12358a commit 7b78c16

File tree

10 files changed

+458
-19
lines changed

10 files changed

+458
-19
lines changed

packages/base/src/Keys.js

+18
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ const isUp = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up
119119

120120
const isDown = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && !hasModifierKeys(event);
121121

122+
const isLeftCtrl = event => (event.key ? (event.key === "ArrowLeft" || event.key === "Left") : event.keyCode === KeyCodes.ARROW_LEFT) && checkModifierKeys(event, true, false, false);
123+
124+
const isRightCtrl = event => (event.key ? (event.key === "ArrowRight" || event.key === "Right") : event.keyCode === KeyCodes.ARROW_RIGHT) && checkModifierKeys(event, true, false, false);
125+
126+
const isUpCtrl = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_UP) && checkModifierKeys(event, true, false, false);
127+
128+
const isDownCtrl = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, false, false);
129+
122130
const isHome = event => (event.key ? event.key === "Home" : event.keyCode === KeyCodes.HOME) && !hasModifierKeys(event);
123131

124132
const isEnd = event => (event.key ? event.key === "End" : event.keyCode === KeyCodes.END) && !hasModifierKeys(event);
@@ -149,6 +157,10 @@ const isPageUpShiftCtrl = event => (event.key ? event.key === "PageUp" : event.k
149157

150158
const isPageDownShiftCtrl = event => (event.key ? event.key === "PageDown" : event.keyCode === KeyCodes.PAGE_DOWN) && checkModifierKeys(event, true, false, true);
151159

160+
const isPlus = event => (event.key ? event.key === "+" : event.keyCode === KeyCodes.PLUS) || (event.keyCode === KeyCodes.NUMPAD_PLUS && !hasModifierKeys(event));
161+
162+
const isMinus = event => (event.key ? event.key === "-" : event.keyCode === KeyCodes.MINUS) || (event.keyCode === KeyCodes.NUMPAD_MINUS && !hasModifierKeys(event));
163+
152164
const isShow = event => {
153165
if (event.key) {
154166
return isF4(event) || isShowByArrows(event);
@@ -182,8 +194,14 @@ export {
182194
isRight,
183195
isUp,
184196
isDown,
197+
isLeftCtrl,
198+
isRightCtrl,
199+
isUpCtrl,
200+
isDownCtrl,
185201
isHome,
186202
isEnd,
203+
isPlus,
204+
isMinus,
187205
isHomeCtrl,
188206
isEndCtrl,
189207
isEscape,

packages/main/src/RangeSlider.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import Float from "@ui5/webcomponents-base/dist/types/Float.js";
22
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
3+
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
34
import SliderBase from "./SliderBase.js";
4-
5-
// Template
65
import RangeSliderTemplate from "./generated/templates/RangeSliderTemplate.lit.js";
76

87
/**
@@ -99,6 +98,10 @@ class RangeSlider extends SliderBase {
9998
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
10099
}
101100

101+
onEnterDOM() {
102+
ResizeHandler.register(this, this._resizeHandler);
103+
}
104+
102105
get tooltipStartValue() {
103106
const stepPrecision = this.constructor._getDecimalPrecisionOfNumber(this._effectiveStep);
104107
return this.startValue.toFixed(stepPrecision);

packages/main/src/Slider.hbs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
{{>include "./SliderBase.hbs"}}
22

33
{{#*inline "handles"}}
4-
<div class="ui5-slider-handle" style="{{styles.handle}}">
4+
<div class="ui5-slider-handle"
5+
style="{{styles.handle}}"
6+
tabindex="{{tabIndex}}"
7+
@focusout="{{_onfocusout}}"
8+
@focusin="{{_onfocusin}}"
9+
data-sap-focus-ref
10+
>
511
{{#if showTooltip}}
612
<div class="ui5-slider-tooltip" style="{{styles.tooltip}}">
713
<span class="ui5-slider-tooltip-value">{{tooltipValue}}</span>

packages/main/src/Slider.js

+51-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Float from "@ui5/webcomponents-base/dist/types/Float.js";
22
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
3+
import { isEscape } from "@ui5/webcomponents-base/dist/Keys.js";
34
import SliderBase from "./SliderBase.js";
45

56
// Template
@@ -82,6 +83,7 @@ class Slider extends SliderBase {
8283
constructor() {
8384
super();
8485
this._stateStorage.value = null;
86+
this._setInitialValue("value", null);
8587
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
8688
}
8789

@@ -121,13 +123,41 @@ class Slider extends SliderBase {
121123
const newValue = this.handleDownBase(event);
122124
this._valueOnInteractionStart = this.value;
123125

126+
// Set initial value if one is not set previously on focus in.
127+
// It will be restored if ESC key is pressed.
128+
if (this._getInitialValue("value") === null) {
129+
this._setInitialValue("value", this.value);
130+
}
131+
124132
// Do not yet update the Slider if press is over a handle. It will be updated if the user drags the mouse.
125133
if (!this._isHandlePressed(this.constructor.getPageXValueFromEvent(event))) {
126134
this._updateHandleAndProgress(newValue);
127135
this.updateValue("value", newValue);
128136
}
129137
}
130138

139+
_onfocusin(event) {
140+
// Set initial value if one is not set previously on focus in.
141+
// It will be restored if ESC key is pressed.
142+
if (this._getInitialValue("value") === null) {
143+
this._setInitialValue("value", this.value);
144+
}
145+
}
146+
147+
_onfocusout(event) {
148+
// Prevent focusout when the focus is getting set within the slider internal
149+
// element (on the handle), before the Slider' customElement itself is finished focusing
150+
if (this._isFocusing()) {
151+
this._preventFocusOut();
152+
return;
153+
}
154+
155+
// Reset focus state and the stored Slider's initial
156+
// value that was saved when it was first focused in
157+
this._setInitialValue("value", null);
158+
}
159+
160+
131161
/**
132162
* Called when the user moves the slider
133163
*
@@ -166,9 +196,7 @@ class Slider extends SliderBase {
166196
* @private
167197
*/
168198
_isHandlePressed(clientX) {
169-
const sliderHandle = this.shadowRoot.querySelector(".ui5-slider-handle");
170-
const sliderHandleDomRect = sliderHandle.getBoundingClientRect();
171-
199+
const sliderHandleDomRect = this._sliderHandle.getBoundingClientRect();
172200
return clientX >= sliderHandleDomRect.left && clientX <= sliderHandleDomRect.right;
173201
}
174202

@@ -187,6 +215,18 @@ class Slider extends SliderBase {
187215
this._handlePositionFromStart = this._progressPercentage * 100;
188216
}
189217

218+
_handleActionKeyPress(event) {
219+
const min = this._effectiveMin;
220+
const max = this._effectiveMax;
221+
const currentValue = this.value;
222+
const newValue = isEscape(event) ? this._getInitialValue("value") : this.constructor.clipValue(this._handleActionKeyPressBase(event, "value") + currentValue, min, max);
223+
224+
if (newValue !== currentValue) {
225+
this._updateHandleAndProgress(newValue);
226+
this.updateValue("value", newValue);
227+
}
228+
}
229+
190230
get styles() {
191231
return {
192232
progress: {
@@ -212,6 +252,10 @@ class Slider extends SliderBase {
212252
};
213253
}
214254

255+
get _sliderHandle() {
256+
return this.shadowRoot.querySelector(".ui5-slider-handle");
257+
}
258+
215259
get labelItems() {
216260
return this._labelItems;
217261
}
@@ -221,6 +265,10 @@ class Slider extends SliderBase {
221265
return this.value.toFixed(stepPrecision);
222266
}
223267

268+
get tabIndexProgress() {
269+
return "-1";
270+
}
271+
224272
static async onDefine() {
225273
await fetchI18nBundle("@ui5/webcomponents");
226274
}

packages/main/src/SliderBase.hbs

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
@touchstart="{{_ontouchstart}}"
55
@mouseover="{{_onmouseover}}"
66
@mouseout="{{_onmouseout}}"
7+
@keydown="{{_onkeydown}}"
8+
@keyup="{{_onkeyup}}"
79
dir="{{effectiveDir}}"
810
>
911
<div class="ui5-slider-inner">
@@ -21,7 +23,7 @@
2123
{{/if}}
2224

2325
<div class="ui5-slider-progress-container">
24-
<div class="ui5-slider-progress" style="{{styles.progress}}"></div>
26+
<div class="ui5-slider-progress" style="{{styles.progress}}" @focusout="{{_onfocusout}}" @focusin="{{_onfocusin}}" tabindex="{{tabIndexProgress}}"></div>
2527
</div>
2628
{{> handles}}
2729
</div>

0 commit comments

Comments
 (0)