Skip to content
Merged
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
9 changes: 5 additions & 4 deletions apps/website/screens/common/example/Example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,18 @@ type ExamplePropTypes = {
};
};

const Example = ({ actionsVisible = true, defaultIsVisible = false, example }: ExamplePropTypes): JSX.Element => {
const Example = ({ actionsVisible = true, defaultIsVisible = false, example }: ExamplePropTypes) => {
const toast = useToast();
const [isCodeVisible, changeIsCodeVisible] = useState(defaultIsVisible);
const [liveCode, setLiveCode] = useState(example.code);

const handleCodeOnClick = () => {
changeIsCodeVisible(!isCodeVisible);
};

const handleCopy = () => {
navigator.clipboard
.writeText(example.code)
.writeText(liveCode)
.then(() => {
toast.success({ message: "Code copied to the clipboard." });
})
Expand All @@ -67,7 +68,7 @@ const Example = ({ actionsVisible = true, defaultIsVisible = false, example }: E

return (
<DxcFlex direction="column" gap="0.75rem">
<LiveProvider code={example.code} scope={example.scope} theme={theme}>
<LiveProvider code={liveCode} scope={example.scope} theme={theme}>
<StyledPreview>
<LivePreview />
<StyledError>
Expand All @@ -87,7 +88,7 @@ const Example = ({ actionsVisible = true, defaultIsVisible = false, example }: E
)}
{isCodeVisible && (
<StyledEditor>
<LiveEditor />
<LiveEditor code={liveCode} onChange={setLiveCode} />
</StyledEditor>
)}
</LiveProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import controlled from "./examples/controlled";
import uncontrolled from "./examples/uncontrolled";
import errorUsage from "./examples/errorHandling";
import TableCode from "@/common/TableCode";
import StatusBadge from "@/common/StatusBadge";

const sections = [
{
Expand Down Expand Up @@ -266,7 +267,27 @@ const sections = [
Specifies a string to be used as the name for the number input element when no <Code>label</Code> is
provided.
</td>
<td>'Number input'</td>
<td>
<TableCode>'Number input'</TableCode>
</td>
</tr>
<tr>
<td>
<DxcFlex direction="column" gap="0.25rem" alignItems="baseline">
<StatusBadge status="new" />
showControls
</DxcFlex>
</td>
<td>
<TableCode>boolean</TableCode>
</td>
<td>
Decides whether the number input has actions to increase or decrease the value, following the defined
step.
</td>
<td>
<TableCode>true</TableCode>
</td>
</tr>
</tbody>
</DxcTable>
Expand Down
4 changes: 4 additions & 0 deletions packages/lib/src/number-input/NumberInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const NumberInput = () => (
<Title title="Without label" theme="light" level={4} />
<DxcNumberInput />
</ExampleContainer>
<ExampleContainer>
<Title title="Without controls" theme="light" level={4} />
<DxcNumberInput showControls={false} />
</ExampleContainer>
<ExampleContainer>
<Title title="With label and placeholder" theme="light" level={4} />
<DxcNumberInput label="Number input" placeholder="Placeholder" />
Expand Down
38 changes: 4 additions & 34 deletions packages/lib/src/number-input/NumberInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ describe("Number input component tests", () => {
expect(number.getAttribute("placeholder")).toBe("Placeholder");
expect(queryAllByRole("button").length).toBe(2);
});

test("Number input is disabled", () => {
const { getByLabelText } = render(<DxcNumberInput label="Number label" disabled />);
const number = getByLabelText("Number label") as HTMLInputElement;
expect(number.disabled).toBeTruthy();
});

test("Number input is read only and cannot be incremented or decremented using the actions", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number label" readOnly />);
const number = getByLabelText("Number label") as HTMLInputElement;
Expand All @@ -42,7 +40,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("");
});

test("Number input is read only and cannot be incremented or decremented using the arrow keys", () => {
const { getByLabelText } = render(<DxcNumberInput label="Number label" readOnly />);
const number = getByLabelText("Number label") as HTMLInputElement;
Expand All @@ -52,12 +49,10 @@ describe("Number input component tests", () => {
fireEvent.keyDown(number, { keyCode: 40 });
expect(number.value).toBe("");
});

test("Number input is optional", () => {
const { getByText } = render(<DxcNumberInput label="Number label" optional />);
expect(getByText("(Optional)")).toBeTruthy();
});

test("Number input is not optional: required field, displays error if not filled in", () => {
const onBlur = jest.fn();
const onChange = jest.fn();
Expand All @@ -73,18 +68,19 @@ describe("Number input component tests", () => {
expect(onChange).toHaveBeenCalled();
expect(onChange).toHaveBeenCalledWith({ value: "", error: "This field is required. Please, enter a value." });
});

test("Hiding number input controls", () => {
const { queryByRole } = render(<DxcNumberInput label="Number label" showControls={false} />);
expect(queryByRole("button")).toBeFalsy();
});
test("Suffix and prefix must be shown", () => {
const { getByText } = render(<DxcNumberInput label="Number input label" prefix="+34" suffix="USD" />);
expect(getByText("+34")).toBeTruthy();
expect(getByText("USD")).toBeTruthy();
});

test("Invalid number input renders error", () => {
const { getByText } = render(<DxcNumberInput error="Error message." />);
expect(getByText("Error message.")).toBeTruthy();
});

test("onChange function is called correctly", () => {
const onChange = jest.fn();
const { getByLabelText } = render(<DxcNumberInput label="Number input label" onChange={onChange} />);
Expand All @@ -96,7 +92,6 @@ describe("Number input component tests", () => {
expect(onChange).toHaveBeenCalledWith({ value: "1" });
expect(number.value).toBe("1");
});

test("Error message is shown if the typed value is less than the min value", () => {
const onChange = jest.fn(({ value, error }) => {
expect(value).toBe("-1");
Expand All @@ -113,7 +108,6 @@ describe("Number input component tests", () => {
userEvent.type(number, "-1");
fireEvent.blur(number);
});

test("Cannot decrement the value if it is less than the min value", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" min={5} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -124,7 +118,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("1");
});

test("Increment the value when it is less than the min value", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" min={5} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -135,7 +128,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("5");
});

test("Error message is shown if the typed value is greater than the max value", () => {
const onChange = jest.fn();
const onBlur = jest.fn();
Expand All @@ -150,7 +142,6 @@ describe("Number input component tests", () => {
expect(onBlur).toHaveBeenCalled();
expect(onBlur).toHaveBeenCalledWith({ value: "12", error: "Value must be less than or equal to 10." });
});

test("Cannot increment the value if it is greater than the max value", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" max={10} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -161,7 +152,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("12");
});

test("Decrement the value when it is greater than the max value", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" max={10} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -172,7 +162,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("10");
});

test("Increment and decrement the value with min and max values", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" min={5} max={10} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -194,7 +183,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("10");
});

test("Increment and decrement the value with an integer step", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" step={5} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -212,7 +200,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("10");
});

test("Increment and decrement the value with a decimal step", async () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" step={0.5} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -232,7 +219,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("-10");
});

test("Increment and decrement the value with min, max and step", async () => {
const onBlur = jest.fn();
const { getByLabelText, getAllByRole } = render(
Expand All @@ -258,7 +244,6 @@ describe("Number input component tests", () => {
expect(number.value).toBe("5");
decrement && (await userEvent.click(decrement));
});

test("Start incrementing from 0 when the min value is less than 0 and the max value is bigger than 0", async () => {
const onBlur = jest.fn();
const { getByLabelText, getAllByRole } = render(
Expand All @@ -271,7 +256,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("2");
});

test("Start incrementing from 0 when the min value is less than 0 and the max is 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={0} step={1} />
Expand All @@ -283,7 +267,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("0");
});

test("Start incrementing from the min value when it is bigger than 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={2} max={10} step={0.5} />
Expand All @@ -295,7 +278,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("2.5");
});

test("Start incrementing from the max value when it is less than 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={-1} step={0.5} />
Expand All @@ -307,7 +289,6 @@ describe("Number input component tests", () => {
increment && (await userEvent.click(increment));
expect(number.value).toBe("-1");
});

test("Start decrementing from 0 when the min value is less than 0 and the max value is bigger than 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={10} step={1} />
Expand All @@ -317,7 +298,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("-1");
});

test("Start decrementing from 0 when the min value is 0 and the max value is bigger than 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={0} max={10} step={1} />
Expand All @@ -327,7 +307,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("0");
});

test("Start decrementing from the min value when it is bigger than 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={2} max={10} step={0.5} />
Expand All @@ -339,7 +318,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("2");
});

test("Start decrementing from the max value when it is less than 0", async () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={-1} step={0.5} />
Expand All @@ -351,7 +329,6 @@ describe("Number input component tests", () => {
decrement && (await userEvent.click(decrement));
expect(number.value).toBe("-1.5");
});

test("Increment and decrement the value with min, max and step using the arrows in keyboard", () => {
const { getByLabelText } = render(<DxcNumberInput label="Number input label" min={5} max={20} step={5} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -375,7 +352,6 @@ describe("Number input component tests", () => {
fireEvent.keyDown(number, { keyCode: 40 });
expect(number.value).toBe("5");
});

test("Value is unchanged when using the scroll wheel in mouse in a disabled input", () => {
const { getByLabelText } = render(
<DxcNumberInput disabled label="Number input label" min={5} max={20} step={5} defaultValue="10" />
Expand All @@ -390,7 +366,6 @@ describe("Number input component tests", () => {
fireEvent.wheel(number, { deltaY: 100 });
expect(number.value).toBe("10");
});

test("Value is unchanged when using the arrows in keyboard in a disabled input", () => {
const { getByLabelText } = render(
<DxcNumberInput disabled label="Number input label" min={5} max={20} step={5} defaultValue="10" />
Expand All @@ -405,7 +380,6 @@ describe("Number input component tests", () => {
fireEvent.keyDown(number, { keyCode: 40 });
expect(number.value).toBe("10");
});

test("Value is unchanged when using the scroll wheel in mouse in a read-only input", () => {
const { getByLabelText } = render(
<DxcNumberInput readOnly label="Number input label" min={5} max={20} step={5} defaultValue="10" />
Expand All @@ -420,7 +394,6 @@ describe("Number input component tests", () => {
fireEvent.wheel(number, { deltaY: 100 });
expect(number.value).toBe("10");
});

test("Value is unchanged when using the arrows in keyboard in a read-only input", () => {
const { getByLabelText } = render(
<DxcNumberInput readOnly label="Number input label" min={5} max={20} step={5} defaultValue="10" />
Expand All @@ -435,7 +408,6 @@ describe("Number input component tests", () => {
fireEvent.keyDown(number, { keyCode: 40 });
expect(number.value).toBe("10");
});

test("Increment and decrement the value with min, max and step using the scroll wheel in mouse", () => {
const { getByLabelText } = render(<DxcNumberInput label="Number input label" min={5} max={20} step={5} />);
const number = getByLabelText("Number input label") as HTMLInputElement;
Expand All @@ -459,7 +431,6 @@ describe("Number input component tests", () => {
fireEvent.wheel(number, { deltaY: 100 });
expect(number.value).toBe("5");
});

test("Number has correct accessibility attributes", () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" />);
const number = getByLabelText("Number input label");
Expand All @@ -472,7 +443,6 @@ describe("Number input component tests", () => {
const increment = getAllByRole("button")[1];
expect(increment?.getAttribute("aria-label")).toBe("Increment value");
});

test("Number input submits correct values inside a form and actions don't trigger the submit event", async () => {
const handlerOnSubmit = jest.fn((e) => {
e.preventDefault();
Expand Down
8 changes: 5 additions & 3 deletions packages/lib/src/number-input/NumberInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,21 @@ const DxcNumberInput = forwardRef<RefType, NumberInputPropsType>(
size,
tabIndex,
ariaLabel = "Number input",
showControls = true,
},
ref
) => {
const numberInputRef = useRef<HTMLInputElement | null>(null);

const contextValue = useMemo(
() => ({
typeNumber: "number",
minNumber: min,
maxNumber: max,
minNumber: min,
showControls,
stepNumber: step,
typeNumber: "number",
}),
[min, max, step]
[max, min, showControls, step]
);

useEffect(() => {
Expand Down
11 changes: 8 additions & 3 deletions packages/lib/src/number-input/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,18 @@ type Props = {
* Specifies a string to be used as the name for the number input element when no `label` is provided.
*/
ariaLabel?: string;
/**
* Decides whether the number input has actions to increase or decrease the value, following the defined step.
*/
showControls?: boolean;
};

export type NumberInputContextProps = {
maxNumber: Props["max"];
minNumber: Props["min"];
showControls: Props["showControls"];
stepNumber: Props["step"];
typeNumber?: string;
minNumber?: number;
maxNumber?: number;
stepNumber?: number;
};

/**
Expand Down
Loading