Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0c75fe7
feat: add scroll event
GDamyanov Oct 31, 2025
69b5eb0
feat: add thousand seperator
GDamyanov Nov 4, 2025
a7578e5
feat: format display value
GDamyanov Nov 4, 2025
decbbda
feat: format value
GDamyanov Nov 5, 2025
6f226ff
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 2, 2025
e48be58
refactor: refactor code
GDamyanov Dec 2, 2025
e809f51
test: add test suites
GDamyanov Dec 3, 2025
9a9b678
refactor: enhance sample
GDamyanov Dec 3, 2025
7a31a1f
fix: lint errors
GDamyanov Dec 3, 2025
612a75d
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 3, 2025
e69b226
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 5, 2025
7c126be
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 5, 2025
a498015
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 9, 2025
c0b0dea
refactor: address review comments
GDamyanov Dec 9, 2025
c74eaf8
refactor: address review comments
GDamyanov Dec 10, 2025
bab220d
fix: remove grouping in NumberFormatter
GDamyanov Dec 10, 2025
3ef8e15
fix: format display value only when it is valid
GDamyanov Dec 10, 2025
0fe4697
chore: add comment in code
GDamyanov Dec 10, 2025
2e1aa82
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 10, 2025
9a96297
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 12, 2025
a9918e8
fix: lint errors
GDamyanov Dec 12, 2025
5830502
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 17, 2025
3ff9c24
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 18, 2025
bb3791f
Merge branch 'main' into stepinput-scroll
GDamyanov Dec 19, 2025
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
8 changes: 8 additions & 0 deletions packages/localization/src/NumberFormat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type NumberFormatT from "sap/ui/core/format/NumberFormat";
// @ts-ignore
import NumberFormatNative from "./sap/ui/core/format/NumberFormat.js";

const NumberFormatWrapped = NumberFormatNative as typeof NumberFormatT;
class NumberFormat extends NumberFormatWrapped {}

export default NumberFormat;
3 changes: 2 additions & 1 deletion packages/localization/used-modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ sap/ui/core/date/Persian.js
sap/ui/core/date/UI5Date.js
sap/ui/core/date/UniversalDate.js
sap/ui/core/format/TimezoneUtil.js
sap/ui/core/format/DateFormat.js
sap/ui/core/format/DateFormat.js
sap/ui/core/format/NumberFormat.js
80 changes: 74 additions & 6 deletions packages/main/cypress/specs/StepInput.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,36 @@ describe("StepInput events", () => {
});
});

describe("StepInput thousand separator formatting", () => {
it("should display value with thousand separator", () => {
cy.mount(
<StepInput value={12345}></StepInput>
);

cy.get("[ui5-step-input]")
.ui5StepInputGetInnerInput()
.should($input => {
const val = $input.val();
// Accepts both comma and dot as separator depending on locale
expect(val).to.match(/12[,.]345/);
});
});

it("should parse formatted value correctly", () => {
cy.mount(
<StepInput value={12345}></StepInput>
);

cy.get("[ui5-step-input]")
.ui5StepInputGetInnerInput()
.should($input => {
const val = $input.val() as string;
const num = Number(val.replace(/[^\d]/g, ""));
expect(num).to.equal(12345);
});
});
});

describe("StepInput property propagation", () => {
it("should propagate 'placeholder' property to inner input", () => {
cy.mount(
Expand All @@ -632,31 +662,33 @@ describe("StepInput property propagation", () => {
.ui5StepInputCheckInnerInputProperty("placeholder", "Enter number");
});

it("should propagate 'min' property to inner input", () => {
it("should not propagate 'min' property to inner input", () => {
cy.mount(
<StepInput min={0}></StepInput>
);

// min should not be propogated because step input uses input with type="text"
cy.get("[ui5-step-input]")
.ui5StepInputCheckInnerInputProperty("min", "0");
.ui5StepInputCheckInnerInputProperty("min", "0", false);
});

it("should propagate 'max' property to inner input", () => {
it("should not propagate 'max' property to inner input", () => {
cy.mount(
<StepInput max={10}></StepInput>
);

// min should not be propogated because step input uses input with type="text"
cy.get("[ui5-step-input]")
.ui5StepInputCheckInnerInputProperty("max", "10");
.ui5StepInputCheckInnerInputProperty("max", "10", false);
});

it("should propagate 'step' property to inner input", () => {
it("should not propagate 'step' property to inner input", () => {
cy.mount(
<StepInput step={2}></StepInput>
);

cy.get("[ui5-step-input]")
.ui5StepInputCheckInnerInputProperty("step", "2");
.ui5StepInputCheckInnerInputProperty("step", "2", false);
});

it("should propagate 'disabled' property to inner input", () => {
Expand Down Expand Up @@ -685,6 +717,42 @@ describe("StepInput property propagation", () => {
cy.get("[ui5-step-input]")
.ui5StepInputCheckInnerInputProperty("value", "5");
});

it("should increase value on mouse wheel up", () => {
cy.mount(
<StepInput value={5} step={2}></StepInput>
);

cy.get("[ui5-step-input]")
.as("stepInput");

cy.get<StepInput>("@stepInput")
.ui5StepInputScrollToChangeValue(7, false);
});

it("should decrease value on mouse wheel down", () => {
cy.mount(
<StepInput value={5} step={2}></StepInput>
);

cy.get("[ui5-step-input]")
.as("stepInput");

cy.get<StepInput>("@stepInput")
.ui5StepInputScrollToChangeValue(3, true);
});

it("should not change value when readonly", () => {
cy.mount(
<StepInput value={5} step={2} readonly={true}></StepInput>
);

cy.get("[ui5-step-input]")
.as("stepInput");

cy.get<StepInput>("@stepInput")
.ui5StepInputScrollToChangeValue(5, true);
});
});

describe("Validation inside form", () => {
Expand Down
47 changes: 43 additions & 4 deletions packages/main/cypress/support/commands/StepInput.commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Cypress.Commands.add("ui5StepInputAttachHandler", { prevSubject: true }, (subje
});
});

Cypress.Commands.add("ui5StepInputCheckInnerInputProperty", { prevSubject: true }, (subject, propName: string, expectedValue: any) => {
Cypress.Commands.add("ui5StepInputGetInnerInput", { prevSubject: true }, (subject) => {
cy.wrap(subject)
.as("stepInput")
.should("be.visible");
Expand All @@ -56,8 +56,16 @@ Cypress.Commands.add("ui5StepInputCheckInnerInputProperty", { prevSubject: true
.find("input")
.as("innerInput");

cy.get("@innerInput")
.should("have.prop", propName, expectedValue);
return cy.get("@innerInput");
});

Cypress.Commands.add("ui5StepInputCheckInnerInputProperty", { prevSubject: true }, (subject, propName: string, expectedValue: any, shouldBePropagated: boolean = true) => {
cy.get(subject)
.ui5StepInputGetInnerInput()
.then($innerInput => {
const condition = shouldBePropagated ? "have.prop" : "not.have.prop";
cy.wrap($innerInput).should(condition, propName, expectedValue);
});
});

Cypress.Commands.add("ui5StepInputTypeNumber", { prevSubject: true }, (subject, value: number) => {
Expand All @@ -75,14 +83,45 @@ Cypress.Commands.add("ui5StepInputTypeNumber", { prevSubject: true }, (subject,
.realPress("Enter");
});

Cypress.Commands.add("ui5StepInputScrollToChangeValue", { prevSubject: true }, (subject, expectedValue: number, decreaseValue: boolean) => {
const deltaY = decreaseValue ? 100 : -100;

cy.wrap(subject)
.as("stepInput")
.should("be.visible");

cy.get("@stepInput")
.realClick();

cy.get("@stepInput")
.should("be.focused");

cy.get("@stepInput")
.shadow()
.find(".ui5-step-input-root")
.then($el => {
const wheelEvent = new WheelEvent("wheel", { deltaY, bubbles: true, cancelable: true });
$el[0].dispatchEvent(wheelEvent);
});

cy.realPress("Tab"); // To trigger change event

cy.get("@stepInput")
.should("have.prop", "value", expectedValue);
});



declare global {
namespace Cypress {
interface Chainable {
ui5StepInputChangeValueWithArrowKeys(expectedValue: number, decreaseValue?: boolean): Chainable<void>
ui5StepInputChangeValueWithButtons(expectedValue: number, decreaseValue?: boolean): Chainable<void>
ui5StepInputAttachHandler(eventName: string, stubName: string): Chainable<void>
ui5StepInputCheckInnerInputProperty(propName: string, expectedValue: any): Chainable<void>
ui5StepInputGetInnerInput(): Chainable<JQuery<HTMLElement>>
ui5StepInputCheckInnerInputProperty(propName: string, expectedValue: any, shouldBePropagated?: boolean): Chainable<void>
ui5StepInputTypeNumber(value: number): Chainable<void>
ui5StepInputScrollToChangeValue(expectedValue: number, decreaseValue: boolean): Chainable<void>
}
}
}
Loading
Loading