diff --git a/packages/main/cypress/specs/Slider.cy.tsx b/packages/main/cypress/specs/Slider.cy.tsx index 05d2c369e3e5..6956bc0cf4b0 100644 --- a/packages/main/cypress/specs/Slider.cy.tsx +++ b/packages/main/cypress/specs/Slider.cy.tsx @@ -1,10 +1,11 @@ import Slider from "../../src/Slider.js"; function dragSliderHandle(selector: string, offset: { x: number, y: number }) { - cy.get(selector).shadow().find(".ui5-slider-handle").realMouseDown() + cy.get(selector).shadow().find("[ui5-slider-handle]").realMouseDown() cy.focused().realMouseMove(offset.x, offset.y); cy.focused().realMouseUp(); } + describe("General interactions", () => { beforeEach(() => { cy.get('[data-cy-root]') @@ -37,45 +38,54 @@ describe("General interactions", () => { cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle-container") - .as("sliderHandleContainer") - .should("have.attr", "style", "left: 0%;"); + .find("[ui5-slider-handle]") + .should("have.attr", "style", "inset-inline-start: clamp(0%, 0%, 100%);"); cy.get("[ui5-slider]").invoke("prop", "value", 3); - cy.get("@sliderHandleContainer") - .should("have.attr", "style", "left: 30%;"); + cy.get("[ui5-slider]") + .shadow() + .find("[ui5-slider-handle]") + .should("have.attr", "style", "inset-inline-start: clamp(0%, 30%, 100%);"); cy.get("[ui5-slider]").realClick(); - cy.get("@sliderHandleContainer") - .should("have.attr", "style", "left: 50%;"); + cy.get("[ui5-slider]") + .shadow() + .find("[ui5-slider-handle]") + .should("have.attr", "style", "inset-inline-start: clamp(0%, 50%, 100%);"); cy.get("[ui5-slider]").should("have.value", 5); cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("sliderHandle"); dragSliderHandle("[ui5-slider]", { x: 300, y: 0 }); - cy.get("@sliderHandleContainer") - .should("have.attr", "style", "left: 70%;"); + cy.get("[ui5-slider]") + .shadow() + .find("[ui5-slider-handle]") + .should("have.attr", "style", "inset-inline-start: clamp(0%, 70%, 100%);"); cy.get("[ui5-slider]").should("have.value", 7); dragSliderHandle("[ui5-slider]", { x: 100, y: 0 }); - cy.get("@sliderHandleContainer") - .should("have.attr", "style", "left: 80%;"); + cy.get("[ui5-slider]") + .shadow() + .find("[ui5-slider-handle]") + .should("have.attr", "style", "inset-inline-start: clamp(0%, 80%, 100%);"); cy.get("[ui5-slider]").should("have.value", 8); dragSliderHandle("[ui5-slider]", { x: -100, y: 0 }); - cy.get("@sliderHandleContainer") - .should("have.attr", "style", "left: 70%;"); + cy.get("[ui5-slider]") + .shadow() + .find("[ui5-slider-handle]") + .should("have.attr", "style", "inset-inline-start: clamp(0%, 70%, 100%);"); cy.get("[ui5-slider]").should("have.value", 7); }); @@ -113,90 +123,6 @@ describe("General interactions", () => { }); }); -describe("Properties synchronization and normalization", () => { - it("If a negative number is set to the step property its positive equivalent should be used as effective value", () => { - cy.mount(); - - cy.get("[ui5-slider]").as("slider"); - - cy.get("@slider").invoke("prop", "step", -7); - - cy.get("@slider").realClick(); - - cy.get("@slider").should("have.value", 1, "The current value should be 'stepified' by 7"); - }); - - it("If the step property or the labelInterval are changed, the tickmarks and labels must be updated also", () => { - cy.mount(); - - cy.get("[ui5-slider]").as("slider"); - - cy.get("@slider").invoke("prop", "step", 1); - - cy.get('@slider') - .its(0) - .its('_labelValues') - .and('have.length', 21); - - cy.get("@slider").invoke("prop", "step", 2); - - cy.get('@slider') - .its(0) - .its('_labelValues') - .and('have.length', 11); - - cy.get("@slider").invoke("prop", "step", 4); - - cy.get('@slider') - .its(0) - .its('_labelValues') - .and('have.length', 6); - }); - - it("If the min and max properties are changed, the tickmarks and labels must be updated also.", () => { - cy.mount(); - - cy.get("[ui5-slider]").as("slider"); - - cy.get('@slider') - .its(0) - .its('_labelValues').should('have.length', 11); - - cy.get("@slider").invoke("prop", "min", 0); - cy.get("@slider").invoke("prop", "max", 20); - - cy.get('@slider') - .its(0) - .its('_labelValues').should('have.length', 11); - }); - - it("If min property is set to a greater number than the max property their effective values should be swapped, their real ones - not", () => { - cy.mount(); - - cy.get("[ui5-slider]").as("slider"); - - cy.get("@slider").invoke("prop", "max").should("equal", 10); - cy.get("@slider").invoke("prop", "min").should("equal", 100); - cy.get("@slider").invoke("prop", "value").should("equal", 10); - }); - - it("Should keep the current value between the boundaries of min and max properties", () => { - cy.mount(); - - cy.get("[ui5-slider]").as("slider"); - - cy.get("@slider").invoke("prop", "min", 100) - cy.get("@slider").invoke("prop", "max", 200) - cy.get("@slider").invoke("prop", "value", 300) - - cy.get("@slider").should("have.value", 200); - - cy.get("@slider").invoke("prop", "value", 99) - - cy.get("@slider").should("have.value", 100); - }); -}); - describe("Slider elements - tooltip, step, tickmarks, labels", () => { beforeEach(() => { cy.get('[data-cy-root]') @@ -210,7 +136,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("@slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .realClick(); dragSliderHandle("#basic-slider-with-tooltip", { x: 240, y: 0 }); @@ -228,7 +154,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("[ui5-slider]").as("slider"); - cy.get("@slider").shadow().find(".ui5-slider-handle").as("sliderHandle"); + cy.get("@slider").shadow().find("[ui5-slider-handle]").as("sliderHandle"); cy.get("@sliderHandle").realClick(); @@ -247,7 +173,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("@slider").invoke("prop", "value", 8); - cy.get("@slider").shadow().find(".ui5-slider-handle").as("sliderHandle"); + cy.get("@slider").shadow().find("[ui5-slider-handle]").as("sliderHandle"); cy.get("@sliderHandle").realClick(); @@ -282,7 +208,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("[ui5-slider]").as("slider"); - cy.get("@slider").shadow().find(".ui5-slider-handle").as("sliderHandle"); + cy.get("@slider").shadow().find("[ui5-slider-handle]").as("sliderHandle"); cy.get("@sliderHandle").realClick(); @@ -317,7 +243,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("[ui5-slider]").as("slider"); - cy.get("@slider").shadow().find(".ui5-slider-handle").as("sliderHandle"); + cy.get("@slider").shadow().find("[ui5-slider-handle]").as("sliderHandle"); cy.get("@sliderHandle").realClick(); @@ -345,7 +271,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.mount(); cy.get("[ui5-slider]").as("slider"); - cy.get("@slider").shadow().find(".ui5-slider-handle").as("sliderHandle"); + cy.get("@slider").shadow().find("[ui5-slider-handle]").as("sliderHandle"); cy.get("@sliderHandle").realClick(); @@ -376,7 +302,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("@slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("sliderHandle"); cy.get("@slider") @@ -412,12 +338,12 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("#slider-tickmarks-labels") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .realClick(); cy.get("#slider-tickmarks-labels") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("be.focused"); cy.realPress("Tab"); @@ -437,7 +363,7 @@ describe("Slider elements - tooltip, step, tickmarks, labels", () => { cy.get("@slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("sliderHandle"); cy.get("@slider") @@ -542,7 +468,7 @@ describe("Accessibility", () => { cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("not.have.attr", "aria-keyshortcuts"); }); @@ -553,7 +479,7 @@ describe("Accessibility", () => { cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("have.attr", "aria-keyshortcuts"); }); @@ -568,7 +494,7 @@ describe("Accessibility", () => { cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("have.attr", "aria-label", `${labelText} Slider handle`); }); @@ -579,7 +505,7 @@ describe("Accessibility", () => { cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("sliderHandle"); cy.get("@sliderHandle") @@ -617,7 +543,7 @@ describe("Accessibility", () => { cy.get("@slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("be.focused"); }); @@ -639,7 +565,7 @@ describe("Accessibility", () => { cy.get("[ui5-slider]") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("be.focused"); }); @@ -659,18 +585,9 @@ describe("Accessibility", () => { cy.get("#basic-slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .should("be.focused"); }); - - it("icon should be correctly displayed", () => { - cy.mount(); - - cy.get("[ui5-slider]") - .shadow() - .find("[ui5-icon]") - .should("have.attr", "name", "direction-arrows"); - }); }); describe("Accessibility: Testing keyboard handling", () => { @@ -685,7 +602,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -703,7 +620,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -721,7 +638,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -739,7 +656,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -757,7 +674,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -775,7 +692,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -793,7 +710,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -811,7 +728,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -829,7 +746,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -847,7 +764,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -865,7 +782,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -883,7 +800,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -901,7 +818,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -919,7 +836,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -937,7 +854,7 @@ describe("Accessibility: Testing keyboard handling", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -970,44 +887,44 @@ describe("Testing resize handling and RTL support", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle-container") + .find("[ui5-slider-handle]") .as("sliderHandleContainer"); cy.get("@slider").invoke("prop", "value", 0); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 0%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 0%, 100%);"); cy.get("@slider").invoke("prop", "value", 3); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 30%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 30%, 100%);"); cy.get("@slider").realClick(); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 50%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 50%, 100%);"); cy.get("@slider").should("have.value", 5); dragSliderHandle("[ui5-slider]", { x: -300, y: 1 }); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 80%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 80%, 100%);"); cy.get("@slider").should("have.value", 8); dragSliderHandle("[ui5-slider]", { x: -100, y: 1 }); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 90%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 90%, 100%);"); cy.get("@slider").should("have.value", 9); dragSliderHandle("[ui5-slider]", { x: -150, y: 1 }); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 100%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 100%, 100%);"); cy.get("@slider").should("have.value", 10); }); @@ -1021,15 +938,15 @@ describe("Testing resize handling and RTL support", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle-container") + .find("[ui5-slider-handle]") .as("sliderHandleContainer"); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 0%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 0%, 100%);"); cy.get("@slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -1039,14 +956,14 @@ describe("Testing resize handling and RTL support", () => { cy.realPress("ArrowLeft"); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 20%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 20%, 100%);"); cy.get("@slider").should("have.value", 2); cy.realPress("ArrowRight"); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 10%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 10%, 100%);"); cy.get("@slider").should("have.value", 1); }); @@ -1061,15 +978,14 @@ describe("Testing resize handling and RTL support", () => { cy.get("[ui5-slider]") .as("slider") .shadow() - .find(".ui5-slider-handle-container") + .find("[ui5-slider-handle]") .as("sliderHandleContainer"); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 0%;"); - + .should("have.attr", "style", "inset-inline-start: clamp(0%, 0%, 100%);"); cy.get("@slider") .shadow() - .find(".ui5-slider-handle") + .find("[ui5-slider-handle]") .as("handle") .realClick(); @@ -1079,14 +995,14 @@ describe("Testing resize handling and RTL support", () => { cy.realPress("ArrowUp"); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 20%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 20%, 100%);"); cy.get("@slider").should("have.value", 2); cy.realPress("ArrowDown"); cy.get("@sliderHandleContainer") - .should("have.attr", "style", "right: 10%;"); + .should("have.attr", "style", "inset-inline-start: clamp(0%, 10%, 100%);"); cy.get("@slider").should("have.value", 1); }); diff --git a/packages/main/src/Slider.ts b/packages/main/src/Slider.ts index 32f61c6b5bc3..47e410c9a083 100644 --- a/packages/main/src/Slider.ts +++ b/packages/main/src/Slider.ts @@ -11,6 +11,7 @@ import type SliderTooltip from "./SliderTooltip.js"; // Template import SliderTemplate from "./SliderTemplate.js"; import type { SliderTooltipChangeEventDetails } from "./SliderTooltip.js"; +import styles from "./generated/themes/Slider.css.js"; // Texts import { @@ -77,6 +78,7 @@ import { tag: "ui5-slider", languageAware: true, formAssociated: true, + styles: [styles], template: SliderTemplate, }) class Slider extends SliderBase implements IFormInputElement { @@ -111,7 +113,6 @@ class Slider extends SliderBase implements IFormInputElement { constructor() { super(); - this._stateStorage.value = undefined; this._lastValidInputValue = this.min.toString(); } @@ -127,12 +128,6 @@ class Slider extends SliderBase implements IFormInputElement { * */ onBeforeRendering() { - if (!this.isCurrentStateOutdated()) { - return; - } - - this.notResized = true; - this.syncUIAndState(); this._updateHandleAndProgress(this.value); } @@ -142,34 +137,8 @@ class Slider extends SliderBase implements IFormInputElement { this.tooltip?.repositionTooltip(); } - syncUIAndState() { - // Validate step and update the stored state for the step property. - if (this.isPropertyUpdated("step")) { - this._validateStep(this.step); - this.storePropertyState("step"); - } - - // Recalculate the tickmarks and labels and update the stored state. - if (this.isPropertyUpdated("min", "max", "value")) { - this.storePropertyState("min", "max"); - - // Here the value props are changed programmatically (not by user interaction) - // and it won't be "stepified" (rounded to the nearest step). 'Clip' them within - // min and max bounderies and update the previous state reference. - this.value = SliderBase.clipValue(this.value, this._effectiveMin, this._effectiveMax); - this.updateStateStorageAndFireInputEvent("value"); - this.storePropertyState("value"); - } - - // Labels must be updated if any of the min/max/step/labelInterval props are changed - if (this.labelInterval && this.showTickmarks) { - this._createLabels(); - } - - // Update the stored state for the labelInterval, if changed - if (this.isPropertyUpdated("labelInterval")) { - this.storePropertyState("labelInterval"); - } + _handleResize() { + // TODO: Remove after refactoring Base and RangeSlider } /** @@ -232,7 +201,7 @@ class Slider extends SliderBase implements IFormInputElement { _onTooltipChange(e: CustomEvent) { const value = parseFloat(e.detail.value); - const isInvalid = value < this._effectiveMin || value > this._effectiveMax; + const isInvalid = value < this.min || value > this.max; if (isInvalid) { this.tooltipValueState = "Negative"; @@ -246,7 +215,7 @@ class Slider extends SliderBase implements IFormInputElement { _onTooltipFocusChange() { const value = parseFloat(this.tooltipValue); - const isInvalid = value < this._effectiveMin || value > this._effectiveMax; + const isInvalid = value < this.min || value > this.max; if (isInvalid) { this.tooltipValueState = "None"; @@ -263,7 +232,7 @@ class Slider extends SliderBase implements IFormInputElement { _onTooltipOpen() { const ctor = this.constructor as typeof Slider; - const stepPrecision = ctor._getDecimalPrecisionOfNumber(this._effectiveStep); + const stepPrecision = ctor._getDecimalPrecisionOfNumber(this.step); this.tooltipValue = this.value.toFixed(stepPrecision); } @@ -278,14 +247,8 @@ class Slider extends SliderBase implements IFormInputElement { _handleMove(e: TouchEvent | MouseEvent) { e.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 ctor = this.constructor as typeof Slider; - const newValue = ctor.getValueFromInteraction(e, this._effectiveStep, this._effectiveMin, this._effectiveMax, this.getBoundingClientRect(), this.directionStart); + const newValue = ctor.getValueFromInteraction(e, this.step, this.min, this.max, this.getBoundingClientRect(), this.directionStart); this._updateHandleAndProgress(newValue); this.value = newValue; @@ -329,8 +292,8 @@ class Slider extends SliderBase implements IFormInputElement { * @private */ _updateHandleAndProgress(newValue: number) { - const max = this._effectiveMax; - const min = this._effectiveMin; + const max = this.max; + const min = this.min; // The progress (completed) percentage of the slider. this._progressPercentage = (newValue - min) / (max - min); @@ -339,8 +302,8 @@ class Slider extends SliderBase implements IFormInputElement { } _handleActionKeyPress(e: KeyboardEvent) { - const min = this._effectiveMin; - const max = this._effectiveMax; + const min = this.min; + const max = this.max; const currentValue = this.value; const ctor = this.constructor as typeof Slider; const newValue = isEscape(e) ? this._valueInitial : ctor.clipValue(this._handleActionKeyPressBase(e, "value") + currentValue, min, max); @@ -367,20 +330,8 @@ class Slider extends SliderBase implements IFormInputElement { return this.getDomRef()?.querySelector("[ui5-slider-tooltip]"); } - get styles() { - return { - progress: { - "width": `${this._handlePositionFromStart}%`, - "border": this._handlePositionFromStart === 0 ? "none" : "", - }, - handle: { - [this.directionStart]: `${this._handlePositionFromStart}%`, - }, - }; - } - get _sliderHandle() : HTMLElement { - return this.shadowRoot!.querySelector(".ui5-slider-handle")!; + return this.shadowRoot!.querySelector("[ui5-slider-handle]")!; } get _ariaDisabled() { @@ -399,19 +350,24 @@ class Slider extends SliderBase implements IFormInputElement { return Slider.i18nBundle.getText(SLIDER_TOOLTIP_INPUT_LABEL); } + // TODO: Refactor these methods after RangeSlider is refactored get tickmarksObject() { - const count = this._tickmarksCount; - const arr = []; + return []; + } - if (this._hiddenTickmarks) { - return [true, false]; - } + _onkeydown(e: KeyboardEvent) { + const target = e.target as HTMLElement; - for (let i = 0; i <= count; i++) { - arr.push(this._effectiveMin + (i * this.step) <= this.value); + if (isF2(e) && target.hasAttribute("ui5-slider-handle")) { + (target.parentNode!.querySelector("[ui5-slider-tooltip]") as HTMLElement).focus(); } - return arr; + if (SliderBase._isActionKey(e) && target && !target.hasAttribute("ui5-slider-tooltip")) { + e.preventDefault(); + + this._isUserInteraction = true; + this._handleActionKeyPress(e); + } } } diff --git a/packages/main/src/SliderHandle.ts b/packages/main/src/SliderHandle.ts new file mode 100644 index 000000000000..4a20b6d61c1c --- /dev/null +++ b/packages/main/src/SliderHandle.ts @@ -0,0 +1,91 @@ +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"; + +/** + * @class + * The ui5-slider-handle component represents the handle of the ui5-slider component. + * + * @constructor + * @extends UI5Element + * @since 2.19.0 + * @private + */ +@customElement({ + tag: "ui5-slider-handle", + renderer: jsxRenderer, + template: SliderHandleTemplate, + styles, +}) +class SliderHandle extends UI5Element { + /** + * Defines the value of the slider handle. + *

+ * Note: The value should be between the min and max properties of the parent ui5-slider. + * @since 2.19.0 + * @public + */ + @property({ type: Number }) + value = 0; + + /** + * Defines the minimum value of the slider handle. + *

+ * Note: The value should be less than the max property of the parent ui5-slider. + * @since 2.19.0 + * @public + */ + @property({ type: Number }) + min = 0; + + /** + * Defines the maximum value of the slider handle. + *

+ * Note: The value should be greater than the min property of the parent ui5-slider. + * @since 2.19.0 + * @public + */ + @property({ type: Number }) + max = 100; + + /** + * Defines whether the slider handle is disabled. + *

+ * Note: A disabled slider handle cannot be interacted with. + * @since 2.19.0 + * @public + */ + @property({ type: Boolean }) + disabled = false; + + /** + * Defines whether the slider handle is active. + *

+ * Note: An active slider handle is currently being interacted with. + * @since 2.19.0 + * @public + */ + @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; + } + + getFocusDomRef(): HTMLElement | undefined { + return this; + } +} + +SliderHandle.define(); + +export default SliderHandle; diff --git a/packages/main/src/SliderHandleTemplate.tsx b/packages/main/src/SliderHandleTemplate.tsx new file mode 100644 index 000000000000..ff12662e0b5f --- /dev/null +++ b/packages/main/src/SliderHandleTemplate.tsx @@ -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 ( +
+ +
+ ); +} diff --git a/packages/main/src/SliderScale.ts b/packages/main/src/SliderScale.ts new file mode 100644 index 000000000000..8cbaf4b94c1c --- /dev/null +++ b/packages/main/src/SliderScale.ts @@ -0,0 +1,271 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import slot from "@ui5/webcomponents-base/dist/decorators/slot.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 ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; +import type { ResizeObserverCallback } from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; +import SliderBase from "./SliderBase.js"; +import SliderScaleTemplate from "./SliderScaleTemplate.js"; + +import SliderScaleCss from "./generated/themes/SliderScale.css.js"; +import type SliderHandle from "./SliderHandle.js"; + +type Tickmark = { + value: number; + label?: string; +}; + +enum SliderScaleOrientation { + /** + * Horizontal orientation + * @public + */ + Horizontal = "Horizontal", + + /** + * Vertical orientation + * @public + */ + Vertical = "Vertical", +} + +@customElement({ + tag: "ui5-slider-scale", + renderer: jsxRenderer, + styles: SliderScaleCss, + template: SliderScaleTemplate, +}) +class SliderScale extends UI5Element { + @property({ type: Number }) + startValue = 0; + + @property({ type: Number }) + endValue = 100; + + @property({ type: Number }) + min = 0; + + @property({ type: Number }) + max = 100; + + @property({ type: Number }) + step = 1; + + @property({ type: Boolean }) + showTickmarks = false; + + @property() + orientation: `${SliderScaleOrientation}` = "Horizontal"; + + @property({ type: Array }) + tickmarks: Array = []; + + @property({ type: Number }) + labelInterval = 0; + + /** + * @private + */ + @property({ type: Number }) + _labelInterval = 1; + + @property({ type: Boolean }) + _labelsOverlapping = false; + + @property({ type: Boolean }) + _hiddenTickmarks = false; + + _resizeHandler: ResizeObserverCallback; + _notResized = true; + + /** + * Defines the component items. + * @public + */ + @slot({ + type: HTMLElement, + "default": true, + }) + handles!: Array; + + static get MIN_LABEL_DISTANCE() { + return 16; + } + + static get MIN_SPACE_BETWEEN_TICKMARKS() { + return 8; + } + + constructor() { + super(); + this._resizeHandler = this._handleResize.bind(this); + } + + onEnterDOM() { + ResizeHandler.register(this, this._resizeHandler); + } + + onExitDOM() { + ResizeHandler.deregister(this, this._resizeHandler); + } + + onAfterRendering() { + if (this._notResized) { + this._handleResize(); + } + } + + /** + * Handle the responsiveness of the SliderScale's UI elements when resizing + * @private + */ + _handleResize() { + if (!this.showTickmarks) { + this._hiddenTickmarks = false; + this._labelsOverlapping = false; + return; + } + + // Mark resizing to avoid unnecessary calls to that function after rendering + this._notResized = false; + + const containerSize = this.orientation === SliderScaleOrientation.Horizontal + ? this.getBoundingClientRect().width + : this.getBoundingClientRect().height; + + const tickmarksCount = this._tickmarksCount; + + // Check if tickmarks should be hidden due to insufficient space + if (tickmarksCount > 1) { + const spaceBetweenTickmarks = containerSize / tickmarksCount; + this._hiddenTickmarks = spaceBetweenTickmarks < SliderScale.MIN_SPACE_BETWEEN_TICKMARKS; + } else { + this._hiddenTickmarks = false; + } + + // Check if labels should be hidden due to insufficient space or overlapping + if (this.labelInterval <= 0 || this._hiddenTickmarks) { + this._labelsOverlapping = true; + } else { + // Calculate if labels would overlap based on their estimated width + const visibleLabelCount = Math.ceil((tickmarksCount - 1) / this.labelInterval) + 1; + const estimatedLabelWidth = 32; // Estimated width in pixels for a label (2rem = ~32px) + const requiredWidth = visibleLabelCount * estimatedLabelWidth; + this._labelsOverlapping = containerSize < requiredWidth; + } + } + + /** + * Calculates space between tickmarks + * @private + */ + _spaceBetweenTickmarks() { + const tickmarksCount = this._tickmarksCount; + if (tickmarksCount <= 1) { + return 0; + } + + const containerSize = this.orientation === SliderScaleOrientation.Horizontal + ? this.getBoundingClientRect().width + : this.getBoundingClientRect().height; + + return containerSize / tickmarksCount; + } + + get _tickmarksCount() { + return (this.max - this.min) / this.step; + } + + get _visibleLabels() { + return this._tickmarks.filter(tick => tick.showLabel); + } + + get _progressStyle() { + const range = this.max - this.min; + // Clamp startValue and endValue to be within min/max bounds + const clampedStartValue = Math.max(this.min, Math.min(this.startValue, this.max)); + const clampedEndValue = Math.max(this.min, Math.min(this.endValue, this.max)); + + const start = ((clampedStartValue - this.min) / range) * 100; + const end = ((clampedEndValue - this.min) / range) * 100; + + if (this.orientation === SliderScaleOrientation.Vertical) { + return { + top: "auto", + bottom: `${start}%`, + height: `${end - start}%`, + }; + } + + return { + insetInlineStart: `${start}%`, + width: `${end - start}%`, + }; + } + + get _allTickmarks() { + // If custom tickmarks are provided, use them + if (this.tickmarks.length > 0) { + return this.tickmarks; + } + + // Otherwise, generate tickmarks based on step + if (!this.showTickmarks) { + return []; + } + + const values = []; + for (let value = this.min; value <= this.max; value += this.step) { + values.push({ value }); + } + return values; + } + + get _tickmarks() { + const allTickmarks = this._allTickmarks; + const stepPrecision = SliderBase._getDecimalPrecisionOfNumber(this.step); + const formatLabelPrecision = stepPrecision > 0 ? stepPrecision : 0; + + if (allTickmarks.length === 0) { + return []; + } + + return allTickmarks.map((tm, index) => { + const value = tm.value; + const isFirstOrLast = index === 0 || index === allTickmarks.length - 1; + const position = ((value - this.min) / (this.max - this.min)) * 100; + + // Determine if this tickmark should be visible + const shouldShowTickmark = this._hiddenTickmarks ? isFirstOrLast : true; + + // Determine if the label should be visible + let showLabel = false; + if (shouldShowTickmark && !this._labelsOverlapping) { + if (this.labelInterval > 0) { + showLabel = index % this.labelInterval === 0; + } else { + showLabel = true; + } + } else if (shouldShowTickmark && this._labelsOverlapping && this.labelInterval > 0) { + // When labels overlap, only show first and last + showLabel = isFirstOrLast; + } + + return { + value, + label: tm.label || value.toFixed(formatLabelPrecision), + isInRange: value >= this.startValue && value <= this.endValue, + position, + showLabel, + visible: shouldShowTickmark, + }; + }).filter(tick => tick.visible); + } +} + +SliderScale.define(); + +export default SliderScale; +export { SliderScaleOrientation }; +export type { Tickmark }; diff --git a/packages/main/src/SliderScaleTemplate.tsx b/packages/main/src/SliderScaleTemplate.tsx new file mode 100644 index 000000000000..6153c8ca2abd --- /dev/null +++ b/packages/main/src/SliderScaleTemplate.tsx @@ -0,0 +1,32 @@ +import type SliderScale from "./SliderScale.js"; + +export default function SliderScaleTemplate(this: SliderScale) { + return ( +
+ {this._tickmarks.length > 0 && ( +
+ {this._tickmarks.map(tick => ( +
+ {tick.label && tick.showLabel && ( + + {tick.label} + + )} +
+ ))} +
+ )} +
+ +
+ ); +} diff --git a/packages/main/src/SliderTemplate.tsx b/packages/main/src/SliderTemplate.tsx index 4c3a7a984a6f..adbab9fc20b7 100644 --- a/packages/main/src/SliderTemplate.tsx +++ b/packages/main/src/SliderTemplate.tsx @@ -1,77 +1,90 @@ -import directionArrows from "@ui5/webcomponents-icons/dist/direction-arrows.js"; import type Slider from "./Slider.js"; -import Icon from "./Icon.js"; -import SliderBaseTemplate from "./SliderBaseTemplate.js"; import SliderTooltip from "./SliderTooltip.js"; +import SliderHandle from "./SliderHandle.js"; +import SliderScale from "./SliderScale.js"; -export default function SliderTemplate(this: Slider) { - return SliderBaseTemplate.call(this, { - progressBar, - handles, - }); -} +const _handlePosition = (min: number, max: number, value: number) => { + const range = max - min; + const position = ((value - min) / range) * 100; + return position; +}; + +const handle = (slider: Slider) => { + const position = _handlePosition(slider.min, slider.max, slider.value); -export function progressBar(this: Slider) { return ( - + <> + + + {tooltip(slider)} + ); -} +}; -export function handles(this: Slider) { +const tooltip = (slider: Slider) => ( + + +); + +export default function SliderTemplate(this: Slider) { return ( -
-
+
- + + {handle(this)} +
- - - -
+ ); } diff --git a/packages/main/src/bundle.esm.ts b/packages/main/src/bundle.esm.ts index 2cbd6114839f..254c43d5ce12 100644 --- a/packages/main/src/bundle.esm.ts +++ b/packages/main/src/bundle.esm.ts @@ -98,6 +98,8 @@ import Select from "./Select.js"; import Option from "./Option.js"; import CustomOption from "./OptionCustom.js"; import Slider from "./Slider.js"; +import SliderHandle from "./SliderHandle.js"; +import SliderScale from "./SliderScale.js"; import SplitButton from "./SplitButton.js"; import StepInput from "./StepInput.js"; import RangeSlider from "./RangeSlider.js"; diff --git a/packages/main/src/themes/Slider.css b/packages/main/src/themes/Slider.css new file mode 100644 index 000000000000..43f1d6ae823a --- /dev/null +++ b/packages/main/src/themes/Slider.css @@ -0,0 +1,32 @@ +@import "./InvisibleTextStyles.css"; +@import "./FormComponents.css"; + +:host { + display: inline-block; + height: var(--_slider_height); + width: 100%; +} + +:host([label-interval]:not([label-interval="0"])) { + height: 3.75rem; + align-items: flex-start; +} + +.ui5-slider-evo-root { + width: 100%; + height: 100%; + display: flex; + align-items: center; + padding: var(--_slider_root_side_padding); + box-sizing: border-box; +} + +:host([disabled]) { + opacity: var(--_ui5_slider_disabled_opacity); + cursor: default; + pointer-events: none; +} + +[ui5-slider-handle] { + z-index: 5; +} diff --git a/packages/main/src/themes/SliderHandle.css b/packages/main/src/themes/SliderHandle.css new file mode 100644 index 000000000000..c65daf3a6b58 --- /dev/null +++ b/packages/main/src/themes/SliderHandle.css @@ -0,0 +1,62 @@ +:host { + background: var(--_ui5_slider_handle_background); + border: var(--_ui5_slider_handle_border); + border-radius: var(--_ui5_slider_handle_border_radius); + position: absolute; + outline: none; + height: var(--_ui5_slider_handle_height); + width: var(--_ui5_slider_handle_width); + box-sizing: var(--_ui5_slider_handle_box_sizing); + display: flex; + justify-content: center; + align-items: center; + z-index: 2; + top: 0; + cursor: pointer; + + margin-inline-start: calc(var(--_ui5_slider_handle_width) / -2 ); + top: 50%; + transform: translateY(-50%); +} + +:host(:focus) { + outline: var(--ui5_slider_handle_outline); + outline-offset: var(--ui5_slider_handle_outline_offset); +} + +:host(:hover) { + background: var(--_ui5_slider_handle_hover_background); + border: var(--_ui5_slider_handle_hover_border); +} + +.ui5-slider-handle-container { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + outline: none; +} + +[slider-icon] { + display: var(--_ui5_slider_handle_icon_display); + color: var(--sapContent_Selected_ForegroundColor); + width: var(--_ui5_slider_handle_icon_size); + height: var(--_ui5_slider_handle_icon_size); +} + +:host(:focus), +:host([active]), +:host(:active) { + [slider-icon] { + display: none; + } + + background-color: var(--_ui5_slider_handle_background_focus); + border: var(--_ui5_slider_handle_focus_border); +} + +:host([orientation="Vertical"]) { + /* rotate */ + transform: rotate(90deg); +} \ No newline at end of file diff --git a/packages/main/src/themes/SliderScale.css b/packages/main/src/themes/SliderScale.css new file mode 100644 index 000000000000..c4b98029d485 --- /dev/null +++ b/packages/main/src/themes/SliderScale.css @@ -0,0 +1,148 @@ +:host { + height: 2rem; + position: relative; + width: 100%; + box-sizing: border-box; + user-select: none; +} + +.ui5-slider-scale-root { + height: .25rem; + top: 50%; + transform: translateY(-50%); +} + +.ui5-slider-scale-root { + box-sizing: var(--_ui5_slider_scale_root_box_sizing); + border-radius: 0.25rem; + width: 100%; + position: relative; + background: var(--ui5_slider_scale_background); + border: var(--_ui5_slider_scale_border); +} + +.ui5-slider-scale-tickmarks-container { + position: absolute; + width: 100%; + height: 100%; + top: 0; + z-index: 5; + display: flex; + justify-content: center; + align-items: center; +} + +.ui5-slider-scale-tickmark { + position: absolute; + height: var(--_ui5_slider_scale_tickmark_height); + border-left: 0.0625rem solid var(--sapField_BorderColor); +} + +.ui5-slider-scale-tickmark-in-range { + border-left-color: var(--sapSlider_Selected_BorderColor); +} + +.ui5-slider-scale-tickmark-label { + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + margin-top: 0.875rem; + font-size: var(--sapFontSmallSize); + color: var(--sapContent_LabelColor); + white-space: nowrap; +} + +.ui5-slider-scale-progress { + position: absolute; + top: var(--_ui5_slider_scale_progress_top); + height: var(--_ui5_slider_scale_progress_height); + background-color: var(--sapSlider_Selected_Background); + border: var(--_ui5_slider_scale_progress_border); + border-left: none; + box-sizing: border-box; + z-index: 4; + border-radius: .25rem; +} + +.ui5-slider-scale-root::before { + content: ""; + position: absolute; + width: .5rem; + height: .5rem; + background-color: var(--sapSlider_Selected_Background); + border: solid 0.0625rem var(--sapContent_Selected_MeasureIndicatorColor); + box-sizing: border-box; + border-radius: 50%; + inset-inline-start: var(--_ui5_slider_scale_dots_distance); + top: 50%; + transform: translateY(-50%); + display: var(--_ui5_slider_scale_dots_display); +} + +.ui5-slider-scale-root::after { + content: ""; + position: absolute; + top: 50%; + right: 0; + width: .5rem; + height: .5rem; + background-color: var(--sapContent_MeasureIndicatorColor); + border-radius: 50%; + border: solid 0.0625rem var(--sapContent_MeasureIndicatorColor); + box-sizing: border-box; + inset-inline-end: var(--_ui5_slider_scale_dots_distance); + top: 50%; + transform: translateY(-50%); + display: var(--_ui5_slider_scale_dots_display); +} + +:host([orientation="Vertical"]) { + width: 2rem; + height: 100%; + + .ui5-slider-scale-root { + box-sizing: border-box; + height: 100%; + width: 0.25rem; + background-color: var(--sapSlider_Background); + position: relative; + } + + .ui5-slider-scale-progress { + width: 100%; + height: auto; + } + + .ui5-slider-scale-root:before { + left: 50%; + top: -1rem; + right: auto; + transform: translateX(-50%); + } + + .ui5-slider-scale-root:after { + left: 50%; + right: auto; + top: auto; + bottom: -1rem; + transform: translateX(-50%); + } + + .ui5-slider-scale-tickmark-label { + margin-top: 0; + margin-left: 14px; + top: 50%; + left: 100%; + transform: translateY(-50%); + } + + .ui5-slider-scale-tickmark { + height: auto; + width: .5rem; + margin-top: 0; + margin-left: 0; + border-left: none; + border-top: 0.0625rem solid var(--sapField_BorderColor); + } +} \ No newline at end of file diff --git a/packages/main/src/themes/base/SliderHandle-parameters.css b/packages/main/src/themes/base/SliderHandle-parameters.css new file mode 100644 index 000000000000..01db4f5ed0d6 --- /dev/null +++ b/packages/main/src/themes/base/SliderHandle-parameters.css @@ -0,0 +1,3 @@ +:host { + --ui5_slider_handle_outline: var(--sapContent_FocusWidth) dotted var(--sapContent_FocusColor); +} \ No newline at end of file diff --git a/packages/main/src/themes/base/SliderScale-parameters.css b/packages/main/src/themes/base/SliderScale-parameters.css new file mode 100644 index 000000000000..8b6c21a396c3 --- /dev/null +++ b/packages/main/src/themes/base/SliderScale-parameters.css @@ -0,0 +1,13 @@ +:host { + --ui5_slider_scale_background: var(--sapSlider_Background); + --_ui5_slider_scale_border: var(--sapSlider_Background); + + --_ui5_slider_scale_dots_distance: -1rem; + --_ui5_slider_scale_tickmark_height: .5rem; +} + +@container style(--ui5_content_density: compact) { + :host { + --_ui5_slider_scale_dots_distance: -.75rem; + } +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3/SliderHandle-parameters.css b/packages/main/src/themes/sap_fiori_3/SliderHandle-parameters.css new file mode 100644 index 000000000000..56f9dcbcbc4b --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline_offset: 1px; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3/SliderScale-parameters.css b/packages/main/src/themes/sap_fiori_3/SliderScale-parameters.css new file mode 100644 index 000000000000..d571531bbc2e --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3/SliderScale-parameters.css @@ -0,0 +1,14 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: border-box; + --_ui5_slider_scale_progress_border: none; + --_ui5_slider_scale_border: none; + --_ui5_slider_scale_progress_height: 100%; + --_ui5_slider_scale_progress_top: 0; + --_ui5_slider_scale_dots_display: inline-block; + + /* Fiori 3 specific */ + --_ui5_slider_scale_dots_display: none; + --_ui5_slider_scale_tickmark_height: 1rem; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3/parameters-bundle.css b/packages/main/src/themes/sap_fiori_3/parameters-bundle.css index fb53a6497f19..31b9a730fb1f 100644 --- a/packages/main/src/themes/sap_fiori_3/parameters-bundle.css +++ b/packages/main/src/themes/sap_fiori_3/parameters-bundle.css @@ -53,6 +53,8 @@ @import "../base/Tokenizer-parameters.css"; @import "../base/ValueStateMessage-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; @import "../base/StepInput-parameters.css"; @import "../base/rtl-parameters.css"; @import "./sizes-parameters.css"; \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_dark/SliderHandle-parameters.css b/packages/main/src/themes/sap_fiori_3_dark/SliderHandle-parameters.css new file mode 100644 index 000000000000..56f9dcbcbc4b --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3_dark/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline_offset: 1px; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_dark/SliderScale-parameters.css b/packages/main/src/themes/sap_fiori_3_dark/SliderScale-parameters.css new file mode 100644 index 000000000000..d571531bbc2e --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3_dark/SliderScale-parameters.css @@ -0,0 +1,14 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: border-box; + --_ui5_slider_scale_progress_border: none; + --_ui5_slider_scale_border: none; + --_ui5_slider_scale_progress_height: 100%; + --_ui5_slider_scale_progress_top: 0; + --_ui5_slider_scale_dots_display: inline-block; + + /* Fiori 3 specific */ + --_ui5_slider_scale_dots_display: none; + --_ui5_slider_scale_tickmark_height: 1rem; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_dark/parameters-bundle.css b/packages/main/src/themes/sap_fiori_3_dark/parameters-bundle.css index b73b056dc46c..42e38287ac25 100644 --- a/packages/main/src/themes/sap_fiori_3_dark/parameters-bundle.css +++ b/packages/main/src/themes/sap_fiori_3_dark/parameters-bundle.css @@ -52,6 +52,8 @@ @import "../base/Tokenizer-parameters.css"; @import "../base/ValueStateMessage-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; @import "../base/StepInput-parameters.css"; @import "../base/rtl-parameters.css"; @import "./sizes-parameters.css"; \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_hcb/SliderHandle-parameters.css b/packages/main/src/themes/sap_fiori_3_hcb/SliderHandle-parameters.css new file mode 100644 index 000000000000..56f9dcbcbc4b --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3_hcb/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline_offset: 1px; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_hcb/SliderScale-parameters.css b/packages/main/src/themes/sap_fiori_3_hcb/SliderScale-parameters.css new file mode 100644 index 000000000000..234ea9ef43aa --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3_hcb/SliderScale-parameters.css @@ -0,0 +1,15 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: content-box; + --_ui5_slider_scale_progress_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_progress_height: 0.375rem; + --_ui5_slider_scale_progress_top: -1px; + --_ui5_slider_scale_dots_display: inline-block; + --ui5_slider_scale_background: var(--sapField_BorderColor); + + /* Fiori 3 specific */ + --_ui5_slider_scale_dots_display: none; + --_ui5_slider_scale_tickmark_height: 1rem; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_hcb/parameters-bundle.css b/packages/main/src/themes/sap_fiori_3_hcb/parameters-bundle.css index aa9aafdd36a1..9f5d9c48d5aa 100644 --- a/packages/main/src/themes/sap_fiori_3_hcb/parameters-bundle.css +++ b/packages/main/src/themes/sap_fiori_3_hcb/parameters-bundle.css @@ -53,6 +53,8 @@ @import "../base/Tokenizer-parameters.css"; @import "./ValueStateMessage-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; @import "../base/StepInput-parameters.css"; @import "./sizes-parameters.css"; @import "../base/rtl-parameters.css"; \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_hcw/SliderHandle-parameters.css b/packages/main/src/themes/sap_fiori_3_hcw/SliderHandle-parameters.css new file mode 100644 index 000000000000..56f9dcbcbc4b --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3_hcw/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline_offset: 1px; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_hcw/SliderScale-parameters.css b/packages/main/src/themes/sap_fiori_3_hcw/SliderScale-parameters.css new file mode 100644 index 000000000000..234ea9ef43aa --- /dev/null +++ b/packages/main/src/themes/sap_fiori_3_hcw/SliderScale-parameters.css @@ -0,0 +1,15 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: content-box; + --_ui5_slider_scale_progress_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_progress_height: 0.375rem; + --_ui5_slider_scale_progress_top: -1px; + --_ui5_slider_scale_dots_display: inline-block; + --ui5_slider_scale_background: var(--sapField_BorderColor); + + /* Fiori 3 specific */ + --_ui5_slider_scale_dots_display: none; + --_ui5_slider_scale_tickmark_height: 1rem; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_fiori_3_hcw/parameters-bundle.css b/packages/main/src/themes/sap_fiori_3_hcw/parameters-bundle.css index 47d6fc215e32..13dfd0c1ceca 100644 --- a/packages/main/src/themes/sap_fiori_3_hcw/parameters-bundle.css +++ b/packages/main/src/themes/sap_fiori_3_hcw/parameters-bundle.css @@ -53,6 +53,8 @@ @import "./ValueStateMessage-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; @import "../base/StepInput-parameters.css"; @import "./sizes-parameters.css"; @import "../base/rtl-parameters.css"; \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon/Slider-parameters.css b/packages/main/src/themes/sap_horizon/Slider-parameters.css new file mode 100644 index 000000000000..da7860b51a09 --- /dev/null +++ b/packages/main/src/themes/sap_horizon/Slider-parameters.css @@ -0,0 +1,11 @@ +:host { + --_slider_root_side_padding: 0 1rem; + --_slider_height: 2.75rem; +} + +@container style(--ui5_content_density: compact) { + :host { + --_slider_root_side_padding: 0 .75rem; + --_slider_height: 2rem; + } +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon/SliderHandle-parameters.css b/packages/main/src/themes/sap_horizon/SliderHandle-parameters.css new file mode 100644 index 000000000000..721230c3be3a --- /dev/null +++ b/packages/main/src/themes/sap_horizon/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline: none; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon/SliderScale-parameters.css b/packages/main/src/themes/sap_horizon/SliderScale-parameters.css new file mode 100644 index 000000000000..387c75be922f --- /dev/null +++ b/packages/main/src/themes/sap_horizon/SliderScale-parameters.css @@ -0,0 +1,10 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: border-box; + --_ui5_slider_scale_progress_border: none; + --_ui5_slider_scale_border: none; + --_ui5_slider_scale_progress_height: 100%; + --_ui5_slider_scale_progress_top: 0; + --_ui5_slider_scale_dots_display: inline-block; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon/parameters-bundle.css b/packages/main/src/themes/sap_horizon/parameters-bundle.css index 30ec253788fd..2a278265c098 100644 --- a/packages/main/src/themes/sap_horizon/parameters-bundle.css +++ b/packages/main/src/themes/sap_horizon/parameters-bundle.css @@ -56,6 +56,9 @@ @import "./Token-parameters.css"; @import "./Tokenizer-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; +@import "./Slider-parameters.css"; @import "./ValueStateMessage-parameters.css"; @import "../base/Toolbar-parameters.css"; @import "./StepInput-parameters.css"; diff --git a/packages/main/src/themes/sap_horizon_dark/Slider-parameters.css b/packages/main/src/themes/sap_horizon_dark/Slider-parameters.css new file mode 100644 index 000000000000..973dde1f5c7c --- /dev/null +++ b/packages/main/src/themes/sap_horizon_dark/Slider-parameters.css @@ -0,0 +1,9 @@ +:host { + --_slider_root_side_padding: 0 1rem; +} + +@container style(--ui5_content_density: compact) { + :host { + --_slider_root_side_padding: 0 .5rem; + } +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_dark/SliderHandle-parameters.css b/packages/main/src/themes/sap_horizon_dark/SliderHandle-parameters.css new file mode 100644 index 000000000000..721230c3be3a --- /dev/null +++ b/packages/main/src/themes/sap_horizon_dark/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline: none; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_dark/SliderScale-parameters.css b/packages/main/src/themes/sap_horizon_dark/SliderScale-parameters.css new file mode 100644 index 000000000000..387c75be922f --- /dev/null +++ b/packages/main/src/themes/sap_horizon_dark/SliderScale-parameters.css @@ -0,0 +1,10 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: border-box; + --_ui5_slider_scale_progress_border: none; + --_ui5_slider_scale_border: none; + --_ui5_slider_scale_progress_height: 100%; + --_ui5_slider_scale_progress_top: 0; + --_ui5_slider_scale_dots_display: inline-block; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_dark/parameters-bundle.css b/packages/main/src/themes/sap_horizon_dark/parameters-bundle.css index e180fefd84fb..f40f6d99ae2f 100644 --- a/packages/main/src/themes/sap_horizon_dark/parameters-bundle.css +++ b/packages/main/src/themes/sap_horizon_dark/parameters-bundle.css @@ -28,6 +28,9 @@ @import "./Link-parameters.css"; @import "./List-parameters.css"; @import "../base/ListItemBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; +@import "./Slider-parameters.css"; @import "./Menu-parameters.css"; @import "./MonthPicker-parameters.css"; @import "./MessageStrip-parameters.css"; diff --git a/packages/main/src/themes/sap_horizon_hcb/SliderHandle-parameters.css b/packages/main/src/themes/sap_horizon_hcb/SliderHandle-parameters.css new file mode 100644 index 000000000000..9abaa383f4ba --- /dev/null +++ b/packages/main/src/themes/sap_horizon_hcb/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline_offset: 3px; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcb/SliderScale-parameters.css b/packages/main/src/themes/sap_horizon_hcb/SliderScale-parameters.css new file mode 100644 index 000000000000..d07d994cffa3 --- /dev/null +++ b/packages/main/src/themes/sap_horizon_hcb/SliderScale-parameters.css @@ -0,0 +1,10 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: content-box; + --_ui5_slider_scale_progress_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_progress_height: 0.375rem; + --_ui5_slider_scale_progress_top: -1px; + --_ui5_slider_scale_dots_display: inline-block; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcb/parameters-bundle.css b/packages/main/src/themes/sap_horizon_hcb/parameters-bundle.css index 144b7b5934e2..8aeac58e3d44 100644 --- a/packages/main/src/themes/sap_horizon_hcb/parameters-bundle.css +++ b/packages/main/src/themes/sap_horizon_hcb/parameters-bundle.css @@ -53,6 +53,8 @@ @import "../base/Tokenizer-parameters.css"; @import "./ValueStateMessage-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; @import "../base/StepInput-parameters.css"; @import "./sizes-parameters.css"; @import "../base/rtl-parameters.css"; \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcw/SliderHandle-parameters.css b/packages/main/src/themes/sap_horizon_hcw/SliderHandle-parameters.css new file mode 100644 index 000000000000..9abaa383f4ba --- /dev/null +++ b/packages/main/src/themes/sap_horizon_hcw/SliderHandle-parameters.css @@ -0,0 +1,5 @@ +@import "../base/SliderHandle-parameters.css"; + +:host { + --ui5_slider_handle_outline_offset: 3px; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcw/SliderScale-parameters.css b/packages/main/src/themes/sap_horizon_hcw/SliderScale-parameters.css new file mode 100644 index 000000000000..d07d994cffa3 --- /dev/null +++ b/packages/main/src/themes/sap_horizon_hcw/SliderScale-parameters.css @@ -0,0 +1,10 @@ +@import "../base/SliderScale-parameters.css"; + +:host { + --_ui5_slider_scale_root_box_sizing: content-box; + --_ui5_slider_scale_progress_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_border: 1px solid var(--sapSlider_Selected_BorderColor); + --_ui5_slider_scale_progress_height: 0.375rem; + --_ui5_slider_scale_progress_top: -1px; + --_ui5_slider_scale_dots_display: inline-block; +} \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcw/parameters-bundle.css b/packages/main/src/themes/sap_horizon_hcw/parameters-bundle.css index 85bd4eb037bb..ab2e8897676f 100644 --- a/packages/main/src/themes/sap_horizon_hcw/parameters-bundle.css +++ b/packages/main/src/themes/sap_horizon_hcw/parameters-bundle.css @@ -53,6 +53,8 @@ @import "../base/Tokenizer-parameters.css"; @import "./ValueStateMessage-parameters.css"; @import "./SliderBase-parameters.css"; +@import "./SliderHandle-parameters.css"; +@import "./SliderScale-parameters.css"; @import "../base/StepInput-parameters.css"; @import "./sizes-parameters.css"; @import "../base/rtl-parameters.css"; \ No newline at end of file