Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
123 changes: 123 additions & 0 deletions packages/main/src/SliderEvolution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import SliderEvolutionTemplate from "./SliderEvolutionTemplate.js";
import SliderScale, { SliderScaleOrientation } from "./SliderScale.js";
import SliderHandle from "./SliderHandle.js";
import styles from "./generated/themes/SliderEvolution.css.js";

@customElement({
tag: "ui5-slider-evolution",
renderer: jsxRenderer,
template: SliderEvolutionTemplate,
styles,
dependencies: [SliderScale, SliderHandle],
})
class SliderEvolution extends UI5Element {
@property({ type: Boolean, noAttribute: true })
_pressed = false;

@property({ type: Number })
value = 0;

@property({ type: Number })
min = 0;

@property({ type: Number })
max = 100;

@property({ type: Number })
step = 1;

@property({ type: Boolean })
showTickmarks = false;

@property({ type: Boolean })
showTickmarkLabels = false;

@property()
orientation: `${SliderScaleOrientation}` = "Horizontal";

get _handlePosition() {
const range = this.max - this.min;
const position = ((this.value - this.min) / range) * 100;
return position;
}

_onmousedown = (e: MouseEvent) => {
const target = e.target as HTMLElement;

this._pressed = true;

if (!this.getDomRef()?.contains(target) || !target.hasAttribute("ui5-slider-handle")) {
this._updateValue(e);
}

document.addEventListener("mouseup", this._onmouseup);
document.addEventListener("mousemove", this._onmousemove);
};

_onmouseup = () => {
this._pressed = false;
document.removeEventListener("mouseup", this._onmouseup);
document.removeEventListener("mousemove", this._onmousemove);
};

_onmousemove = (e: MouseEvent) => {
if (this._pressed) {
this._updateValue(e);
}
};

_updateValue(e: MouseEvent) {
const rect = this.getBoundingClientRect();
let percentage = 0;

if (this.orientation === SliderScaleOrientation.Horizontal) {
if (this.effectiveDir === "rtl") {
const x = e.clientX - rect.left;
percentage = 1 - x / rect.width;
} else {
const x = e.clientX - rect.left;
percentage = x / rect.width;
}
} else {
const y = e.clientY - rect.top;
percentage = 1 - y / rect.height;
}

let value = this.min + percentage * (this.max - this.min);

value = Math.round(value / this.step) * this.step;

if (value < this.min) {
value = this.min;
}
if (value > this.max) {
value = this.max;
}

this.value = value;
}

keydown(e: KeyboardEvent) {
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
this.value = Math.min(this.value + this.step, this.max);
e.preventDefault();
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
this.value = Math.max(this.value - this.step, this.min);
e.preventDefault();
} else if (e.key === "Home") {
this.value = this.min;
e.preventDefault();
} else if (e.key === "End") {
this.value = this.max;
e.preventDefault();
}
};

Check failure on line 118 in packages/main/src/SliderEvolution.ts

View workflow job for this annotation

GitHub Actions / check

Unnecessary semicolon
}

SliderEvolution.define();

export default SliderEvolution;
58 changes: 58 additions & 0 deletions packages/main/src/SliderEvolutionTemplate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type SliderEvolution from "./SliderEvolution.js";
import SliderScale from "./SliderScale.js";
import SliderHandle from "./SliderHandle.js";
import { getScopedVarName } from "@ui5/webcomponents-base/dist/CustomElementsScopeUtils.js";

export default function SliderEvolutionTemplate(this: SliderEvolution) {
const _handlePosition = () => {
const range = this.max - this.min;
const position = ((this.value - this.min) / range) * 100;
return position;
};

const _handleVerticalPosition = () => {
const range = this.max - this.min;
const position = ((this.value - this.min) / range) * 100;
return position;
};

const calcHandlePosition = () => {
if (this.orientation === "Vertical") {
return `calc(${_handleVerticalPosition()}% - calc(var(${getScopedVarName("--_ui5_slider_handle_height")}) / 2))`;
}

if (this.effectiveDir === "rtl") {
return `calc(${100 - _handlePosition()}% - calc(var(${getScopedVarName("--_ui5_slider_handle_width")}) / 2))`;
}

return `calc(${_handlePosition()}% - calc(var(${getScopedVarName("--_ui5_slider_handle_width")}) / 2))`;
};

return (
<div
class="ui5-slider-evolution-root"
onMouseDown={this._onmousedown}
>
<SliderScale
min={this.min}
max={this.max}
step={this.step}
startValue={this.min}
endValue={this.value}
show-tickmarks={this.showTickmarks}
show-tickmark-labels={this.showTickmarkLabels}
orientation={this.orientation}
/>
<SliderHandle
active={this._pressed}
orientation={this.orientation}
onKeyDown={this.keydown}
style={{
left: this.orientation === "Vertical" ? "0" : calcHandlePosition(),
bottom: this.orientation === "Vertical" ? calcHandlePosition() : 0,
top: this.orientation === "Vertical" ? "auto" : "4px"
}}
/>
</div>
);
}
43 changes: 43 additions & 0 deletions packages/main/src/SliderHandle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import SliderHandleTemplate from "./SliderHandleTemplate.js";
import styles from "./generated/themes/SliderHandle.css.js";
import type { SliderScaleOrientation } from "./SliderScale.js";

@customElement({
tag: "ui5-slider-handle",
renderer: jsxRenderer,
template: SliderHandleTemplate,
styles,
})
class SliderHandle extends UI5Element {
@property({ type: Number })
value = 0;

@property({ type: Number })
min = 0;

@property({ type: Number })
max = 100;

@property({ type: Boolean })
disabled = false;

@property({ type: Boolean })
active = false;

@property()
orientation: `${SliderScaleOrientation}` = "Horizontal";

get _handlePosition() {
const range = this.max - this.min;
const position = ((this.value - this.min) / range) * 100;
return position;
}
}

SliderHandle.define();

export default SliderHandle;
15 changes: 15 additions & 0 deletions packages/main/src/SliderHandleTemplate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import directionArrows from "@ui5/webcomponents-icons/dist/direction-arrows.js";
import Icon from "./Icon.js";
import type SliderHandle from "./SliderHandle.js";

export default function SliderHandleTemplate(this: SliderHandle) {
return (
<div class="ui5-slider-handle-container" part="handle-container" tabIndex={1}>
<Icon name={directionArrows}
mode="Decorative"
part="icon-slider"
slider-icon
></Icon>
</div>
);
}
Loading
Loading