-
Notifications
You must be signed in to change notification settings - Fork 275
feat(ui5-slider): Add Slider component #2349
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
Changes from 45 commits
92d3e95
c67f585
831da57
cd7e00d
1954979
415da4e
f99f666
15f3eaf
68d3400
b671445
5eb2b54
a6c4b34
5c26fc7
dd58f68
67da54a
ce40132
97afe65
db2f2fa
a825d06
74ccf26
004f97b
d6014de
db456ef
1705983
652de00
577c688
494694b
0e5e881
d9c9d87
ecc630f
e692495
04685d6
da25fb0
e0a2350
2c567d8
f2397a8
92055bc
dfd9375
0e4d37c
3b68e23
0d878b0
29f5f5f
cb80ab4
c9c0e0b
a485770
26be6ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
[1115/190746.143:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/190746.146:ERROR:exception_snapshot_win.cc(99)] thread ID 24416 not found in process | ||
[1115/200309.808:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/200309.809:ERROR:exception_snapshot_win.cc(99)] thread ID 37412 not found in process | ||
[1115/200309.831:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/200309.832:ERROR:exception_snapshot_win.cc(99)] thread ID 32636 not found in process | ||
[1115/200417.889:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/200417.891:ERROR:exception_snapshot_win.cc(99)] thread ID 49336 not found in process | ||
[1115/200417.910:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/200417.910:ERROR:exception_snapshot_win.cc(99)] thread ID 25108 not found in process | ||
[1115/200518.134:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/200518.136:ERROR:exception_snapshot_win.cc(99)] thread ID 39420 not found in process | ||
[1115/200518.155:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/200518.156:ERROR:exception_snapshot_win.cc(99)] thread ID 32120 not found in process | ||
[1115/222805.032:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/222805.034:ERROR:exception_snapshot_win.cc(99)] thread ID 26132 not found in process | ||
[1115/222805.054:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/222805.054:ERROR:exception_snapshot_win.cc(99)] thread ID 52764 not found in process | ||
[1115/222843.639:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/222843.641:ERROR:exception_snapshot_win.cc(99)] thread ID 55836 not found in process | ||
[1115/222843.663:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/222843.663:ERROR:exception_snapshot_win.cc(99)] thread ID 10768 not found in process | ||
[1115/235527.379:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/235527.381:ERROR:exception_snapshot_win.cc(99)] thread ID 15440 not found in process | ||
[1115/235637.656:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/235637.659:ERROR:exception_snapshot_win.cc(99)] thread ID 37192 not found in process | ||
[1115/235637.686:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1115/235637.686:ERROR:exception_snapshot_win.cc(99)] thread ID 16908 not found in process | ||
[1116/000415.338:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1116/000415.341:ERROR:exception_snapshot_win.cc(99)] thread ID 35368 not found in process | ||
[1116/000437.669:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1116/000437.671:ERROR:exception_snapshot_win.cc(99)] thread ID 34420 not found in process | ||
[1116/073652.537:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1116/073652.538:ERROR:exception_snapshot_win.cc(99)] thread ID 50460 not found in process | ||
[1116/073652.554:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) | ||
[1116/073652.554:ERROR:exception_snapshot_win.cc(99)] thread ID 43292 not found in process |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{{>include "./SliderBase.hbs"}} | ||
|
||
{{#*inline "handles"}} | ||
<div class="ui5-slider-handle" style="{{styles.handle}}"> | ||
{{#if showTooltip}} | ||
<div class="ui5-slider-tooltip" style="{{styles.tooltip}}"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tooltip is not in the static area. Was that discussed? Probably the tooltip can be cut if there are overflow: hidden elements on the page. I guess it's not the biggest issue and makes the implementation much simpler. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. this was not discussed previously. It will be good if it is ok to refactor this in the near future. |
||
<span class="ui5-slider-tooltip-value">{{tooltipValue}}</span> | ||
</div> | ||
{{/if}} | ||
</div> | ||
{{/inline}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
import Float from "@ui5/webcomponents-base/dist/types/Float.js"; | ||
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; | ||
import SliderBase from "./SliderBase.js"; | ||
|
||
// Template | ||
import SliderTemplate from "./generated/templates/SliderTemplate.lit.js"; | ||
|
||
/** | ||
* @public | ||
*/ | ||
const metadata = { | ||
tag: "ui5-slider", | ||
languageAware: true, | ||
managedSlots: true, | ||
properties: /** @lends sap.ui.webcomponents.main.Slider.prototype */ { | ||
/** | ||
* Current value of the slider | ||
* | ||
* @type {Float} | ||
* @defaultvalue 0 | ||
* @public | ||
*/ | ||
value: { | ||
ndeshev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
type: Float, | ||
defaultValue: 0, | ||
}, | ||
}, | ||
}; | ||
|
||
/** | ||
* @class | ||
* | ||
* <h3 class="comment-api-title">Overview</h3> | ||
ndeshev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* The Slider component represents a numerical range and a handle (grip). | ||
ndeshev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* The purpose of the component is to enable visual selection of a value in | ||
* a continuous numerical range by moving an adjustable handle. | ||
* | ||
* <h3>Structure</h3> | ||
* The most important properties of the Slider are: | ||
* <ul> | ||
* <li>min - The minimum value of the slider range</li> | ||
* <li>max - The maximum value of the slider range</li> | ||
* <li>value - The current value of the slider</li> | ||
* <li>step - Determines the increments in which the slider will move</li> | ||
* <li>showTooltip - Determines if a tooltip should be displayed above the handle</li> | ||
* <li>showTickmarks - Displays a visual divider between the step values</li> | ||
* <li>labelInterval - Labels some or all of the tickmarks with their values.</li> | ||
* </ul> | ||
* | ||
* <h3>Usage</h3> | ||
* The most common usecase is to select values on a continuous numerical scale (e.g. temperature, volume, etc. ). | ||
* | ||
* <h3>Responsive Behavior</h3> | ||
* The <code>ui5-slider</code> component adjusts to the size of its parent container by recalculating and | ||
* resizing the width of the control. You can move the slider handle in several different ways: | ||
* <ul> | ||
* <li>Drag and drop to the desired value</li> | ||
* <li>Click/tap on the range bar to move the handle to that location</li> | ||
* </ul> | ||
* | ||
* <h3>ES6 Module Import</h3> | ||
* | ||
* <code>import "@ui5/webcomponents/dist/Slider";</code> | ||
* | ||
* @constructor | ||
* @author SAP SE | ||
* @alias sap.ui.webcomponents.main.Slider | ||
* @extends sap.ui.webcomponents.base.UI5Element | ||
* @tagname ui5-slider | ||
* @since 1.0.0-rc.11 | ||
* @appenddocs SliderBase | ||
* @public | ||
*/ | ||
class Slider extends SliderBase { | ||
static get metadata() { | ||
return metadata; | ||
} | ||
|
||
static get template() { | ||
return SliderTemplate; | ||
} | ||
|
||
constructor() { | ||
super(); | ||
this._stateStorage.value = null; | ||
this.i18nBundle = getI18nBundle("@ui5/webcomponents"); | ||
} | ||
|
||
/** | ||
* | ||
* Check if the previously saved state is outdated. That would mean | ||
* either it is the initial rendering or that a property has been changed | ||
* programatically - because the previous state is always updated in | ||
* the interaction handlers. | ||
* | ||
* Normalize current properties, update the previously stored state. | ||
* Update the visual UI representation of the Slider | ||
* | ||
*/ | ||
onBeforeRendering() { | ||
if (!this.isCurrentStateOutdated()) { | ||
return; | ||
} | ||
|
||
this.notResized = true; | ||
this.syncUIAndState("value"); | ||
this._updateHandleAndProgress(this.value); | ||
} | ||
|
||
/** | ||
* Called when the user starts interacting with the slider | ||
* | ||
* @private | ||
*/ | ||
_onmousedown(event) { | ||
// If step is 0 no interaction is available because there is no constant | ||
// (equal for all user environments) quantitative representation of the value | ||
if (this.disabled || this.step === 0) { | ||
return; | ||
} | ||
|
||
const newValue = this.handleDownBase(event, this._effectiveMin, this._effectiveMax); | ||
|
||
// 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); | ||
} | ||
} | ||
|
||
/** | ||
* Called when the user moves the slider | ||
* | ||
* @private | ||
*/ | ||
_handleMove(event) { | ||
event.preventDefault(); | ||
|
||
// If step is 0 no interaction is available because there is no constant | ||
// (equal for all user environments) quantitative representation of the value | ||
if (this.disabled || this._effectiveStep === 0) { | ||
return; | ||
} | ||
|
||
const newValue = this.constructor.getValueFromInteraction(event, this._effectiveStep, this._effectiveMin, this._effectiveMax, this.getBoundingClientRect(), this.directionStart); | ||
|
||
this._updateHandleAndProgress(newValue); | ||
this.updateValue("value", newValue); | ||
} | ||
|
||
/** Called when the user finish interacting with the slider | ||
* | ||
* @private | ||
*/ | ||
_handleUp(event) { | ||
this.handleUpBase(); | ||
} | ||
|
||
/** Determines if the press is over the handle | ||
* | ||
* @private | ||
*/ | ||
_isHandlePressed(clientX) { | ||
const sliderHandle = this.shadowRoot.querySelector(".ui5-slider-handle"); | ||
const sliderHandleDomRect = sliderHandle.getBoundingClientRect(); | ||
|
||
return clientX >= sliderHandleDomRect.left && clientX <= sliderHandleDomRect.right; | ||
} | ||
|
||
|
||
/** Updates the UI representation of the progress bar and handle position | ||
* | ||
* @private | ||
*/ | ||
_updateHandleAndProgress(newValue) { | ||
const max = this._effectiveMax; | ||
const min = this._effectiveMin; | ||
|
||
// The progress (completed) percentage of the slider. | ||
this._progressPercentage = (newValue - min) / (max - min); | ||
// How many pixels from the left end of the slider will be the placed the affected by the user action handle | ||
this._handlePositionFromStart = this._progressPercentage * 100; | ||
} | ||
|
||
get styles() { | ||
return { | ||
progress: { | ||
"transform": `scaleX(${this._progressPercentage})`, | ||
"transform-origin": `${this.directionStart} top`, | ||
}, | ||
handle: { | ||
[this.directionStart]: `${this._handlePositionFromStart}%`, | ||
}, | ||
tickmarks: { | ||
"background": `${this._tickmarks}`, | ||
}, | ||
label: { | ||
"width": `${this._labelWidth}%`, | ||
}, | ||
labelContainer: { | ||
"width": `100%`, | ||
[this.directionStart]: `-${this._labelWidth / 2}%`, | ||
}, | ||
tooltip: { | ||
"visibility": `${this._tooltipVisibility}`, | ||
}, | ||
}; | ||
} | ||
|
||
get labelItems() { | ||
return this._labelItems; | ||
} | ||
|
||
get tooltipValue() { | ||
const stepPrecision = this.constructor._getDecimalPrecisionOfNumber(this._effectiveStep); | ||
return this.value.toFixed(stepPrecision); | ||
} | ||
|
||
static async onDefine() { | ||
await fetchI18nBundle("@ui5/webcomponents"); | ||
} | ||
} | ||
|
||
Slider.define(); | ||
|
||
export default Slider; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<div | ||
ilhan007 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
class="ui5-slider-root" | ||
@mousedown="{{_onmousedown}}" | ||
@touchstart="{{_ontouchstart}}" | ||
@mouseover="{{_onmouseover}}" | ||
@mouseout="{{_onmouseout}}" | ||
dir="{{effectiveDir}}" | ||
> | ||
<div class="ui5-slider-inner"> | ||
<div class="ui5-slider-progress-container"> | ||
<div class="ui5-slider-progress" style="{{styles.progress}}"></div> | ||
</div> | ||
|
||
{{#if step}} | ||
{{#if showTickmarks}} | ||
<div class="ui5-slider-tickmarks" style="{{styles.tickmarks}}"></div> | ||
{{#if labelInterval}} | ||
<ul class="ui5-slider-labels {{classes.labelContainer}}" style="{{styles.labelContainer}}"> | ||
{{#each _labels}} | ||
<li style="{{../styles.label}}">{{this}}</li> | ||
{{/each}} | ||
</ul> | ||
{{/if}} | ||
{{/if}} | ||
{{/if}} | ||
{{> handles}} | ||
</div> | ||
</div> | ||
|
||
{{#*inline "handles"}}{{/inline}} |
Uh oh!
There was an error while loading. Please reload this page.