Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui5-slider): focus and keyboard handling implementation #2614

Merged
merged 16 commits into from
Jan 11, 2021
Merged
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/base/src/Keys.js
Original file line number Diff line number Diff line change
@@ -115,6 +115,14 @@ const isUp = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up

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

const isLeftCtrl = event => (event.key ? (event.key === "ArrowLeft" || event.key === "Left") : event.keyCode === KeyCodes.ARROW_LEFT) && checkModifierKeys(event, true, false, false);

const isRightCtrl = event => (event.key ? (event.key === "ArrowRight" || event.key === "Right") : event.keyCode === KeyCodes.ARROW_RIGHT) && checkModifierKeys(event, true, false, false);

const isUpCtrl = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_UP) && checkModifierKeys(event, true, false, false);

const isDownCtrl = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, false, false);

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);
@@ -145,6 +153,10 @@ const isPageUpShiftCtrl = event => (event.key ? event.key === "PageUp" : event.k

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

const isPlus = event => (event.key ? event.key === "+" : event.keyCode === KeyCodes.PLUS) || (event.keyCode === KeyCodes.NUMPAD_PLUS && !hasModifierKeys(event));

const isMinus = event => (event.key ? event.key === "-" : event.keyCode === KeyCodes.MINUS) || (event.keyCode === KeyCodes.NUMPAD_MINUS && !hasModifierKeys(event));

const isShow = event => {
if (event.key) {
return isF4(event) || isShowByArrows(event);
@@ -176,8 +188,14 @@ export {
isRight,
isUp,
isDown,
isLeftCtrl,
isRightCtrl,
isUpCtrl,
isDownCtrl,
isHome,
isEnd,
isPlus,
isMinus,
isHomeCtrl,
isEndCtrl,
isEscape,
7 changes: 5 additions & 2 deletions packages/main/src/RangeSlider.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import Float from "@ui5/webcomponents-base/dist/types/Float.js";
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
import SliderBase from "./SliderBase.js";

// Template
import RangeSliderTemplate from "./generated/templates/RangeSliderTemplate.lit.js";

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

onEnterDOM() {
ResizeHandler.register(this, this._resizeHandler);
}

get tooltipStartValue() {
const stepPrecision = this.constructor._getDecimalPrecisionOfNumber(this._effectiveStep);
return this.startValue.toFixed(stepPrecision);
2 changes: 1 addition & 1 deletion packages/main/src/Slider.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{>include "./SliderBase.hbs"}}

{{#*inline "handles"}}
<div class="ui5-slider-handle" style="{{styles.handle}}">
<div class="ui5-slider-handle" style="{{styles.handle}}" tabindex="{{tabIndex}}" @focusout="{{_onfocusout}}" @focusin="{{_onfocusin}}">
{{#if showTooltip}}
<div class="ui5-slider-tooltip" style="{{styles.tooltip}}">
<span class="ui5-slider-tooltip-value">{{tooltipValue}}</span>
63 changes: 60 additions & 3 deletions packages/main/src/Slider.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Float from "@ui5/webcomponents-base/dist/types/Float.js";
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import { isEscape } from "@ui5/webcomponents-base/dist/Keys.js";
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
import SliderBase from "./SliderBase.js";

// Template
@@ -82,9 +84,15 @@ class Slider extends SliderBase {
constructor() {
super();
this._stateStorage.value = null;
this._setInitialValue("value", null);
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
}

onEnterDOM() {
this._sliderHandle = this.shadowRoot.querySelector(".ui5-slider-handle");
ResizeHandler.register(this, this._resizeHandler);
}

/**
*
* Check if the previously saved state is outdated. That would mean
@@ -106,6 +114,10 @@ class Slider extends SliderBase {
this._updateHandleAndProgress(this.value);
}

focusInnerElement() {
this._sliderHandle.focus();
}

/**
* Called when the user starts interacting with the slider
*
@@ -121,13 +133,44 @@ class Slider extends SliderBase {
const newValue = this.handleDownBase(event);
this._valueOnInteractionStart = this.value;

// Set initial value if one is not set previously on focus in.
// It will be restored if ESC key is pressed.
if (this._getInitialValue("value") === null) {
this._setInitialValue("value", this.value);
}

// Do not yet update the Slider if press is over a handle. It will be updated if the user drags the mouse.
if (!this._isHandlePressed(this.constructor.getPageXValueFromEvent(event))) {
this._updateHandleAndProgress(newValue);
this.updateValue("value", newValue);
}
}

_onfocusin(event) {
// Set initial value if one is not set previously on focus in.
// It will be restored if ESC key is pressed.
if (this._getInitialValue("value") === null) {
this._setInitialValue("value", this.value);
}

this.focused = true;
}

_onfocusout(event) {
// Prevent focusout when the focus is getting set within the slider internal
// element (on the handle), before the Slider' customElement itself is finished focusing
if (this._isFocusing()) {
this._preventFocusOut();
return;
}

// Reset focus state and the stored Slider's initial
// value that was saved when it was first focused in
this.focused = false;
this._setInitialValue("value", null);
}


/**
* Called when the user moves the slider
*
@@ -166,9 +209,7 @@ class Slider extends SliderBase {
* @private
*/
_isHandlePressed(clientX) {
const sliderHandle = this.shadowRoot.querySelector(".ui5-slider-handle");
const sliderHandleDomRect = sliderHandle.getBoundingClientRect();

const sliderHandleDomRect = this._sliderHandle.getBoundingClientRect();
return clientX >= sliderHandleDomRect.left && clientX <= sliderHandleDomRect.right;
}

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

_handleActionKeyPress(event) {
const min = this._effectiveMin;
const max = this._effectiveMax;
const currentValue = this.value;
const newValue = isEscape(event) ? this._getInitialValue("value") : this.constructor.clipValue(this._handleActionKeyPressBase(event, "value") + currentValue, min, max);

if (newValue !== currentValue) {
this._updateHandleAndProgress(newValue);
this.updateValue("value", newValue);
}
}

get styles() {
return {
progress: {
@@ -221,6 +274,10 @@ class Slider extends SliderBase {
return this.value.toFixed(stepPrecision);
}

get tabIndexProgress() {
return "-1";
}

static async onDefine() {
await fetchI18nBundle("@ui5/webcomponents");
}
4 changes: 3 additions & 1 deletion packages/main/src/SliderBase.hbs
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@
@touchstart="{{_ontouchstart}}"
@mouseover="{{_onmouseover}}"
@mouseout="{{_onmouseout}}"
@keydown="{{_onkeydown}}"
@keyup="{{_onkeyup}}"
dir="{{effectiveDir}}"
>
<div class="ui5-slider-inner">
@@ -21,7 +23,7 @@
{{/if}}

<div class="ui5-slider-progress-container">
<div class="ui5-slider-progress" style="{{styles.progress}}"></div>
<div class="ui5-slider-progress" style="{{styles.progress}}" @focusout="{{_onfocusout}}" @focusin="{{_onfocusin}}" tabindex="{{tabIndexProgress}}"></div>
</div>
{{> handles}}
</div>
Loading