Skip to content

Commit 7e9af4c

Browse files
authored
Merge pull request #2171 from dxc-technology/gomezivann/numberInput-show-controls
Number input new prop `showControls`
2 parents 157878e + 23ca6f3 commit 7e9af4c

File tree

7 files changed

+50
-47
lines changed

7 files changed

+50
-47
lines changed

apps/website/screens/common/example/Example.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,18 @@ type ExamplePropTypes = {
4646
};
4747
};
4848

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

5354
const handleCodeOnClick = () => {
5455
changeIsCodeVisible(!isCodeVisible);
5556
};
5657

5758
const handleCopy = () => {
5859
navigator.clipboard
59-
.writeText(example.code)
60+
.writeText(liveCode)
6061
.then(() => {
6162
toast.success({ message: "Code copied to the clipboard." });
6263
})
@@ -67,7 +68,7 @@ const Example = ({ actionsVisible = true, defaultIsVisible = false, example }: E
6768

6869
return (
6970
<DxcFlex direction="column" gap="0.75rem">
70-
<LiveProvider code={example.code} scope={example.scope} theme={theme}>
71+
<LiveProvider code={liveCode} scope={example.scope} theme={theme}>
7172
<StyledPreview>
7273
<LivePreview />
7374
<StyledError>
@@ -87,7 +88,7 @@ const Example = ({ actionsVisible = true, defaultIsVisible = false, example }: E
8788
)}
8889
{isCodeVisible && (
8990
<StyledEditor>
90-
<LiveEditor />
91+
<LiveEditor code={liveCode} onChange={setLiveCode} />
9192
</StyledEditor>
9293
)}
9394
</LiveProvider>

apps/website/screens/components/number-input/code/NumberInputCodePage.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import controlled from "./examples/controlled";
88
import uncontrolled from "./examples/uncontrolled";
99
import errorUsage from "./examples/errorHandling";
1010
import TableCode from "@/common/TableCode";
11+
import StatusBadge from "@/common/StatusBadge";
1112

1213
const sections = [
1314
{
@@ -266,7 +267,27 @@ const sections = [
266267
Specifies a string to be used as the name for the number input element when no <Code>label</Code> is
267268
provided.
268269
</td>
269-
<td>'Number input'</td>
270+
<td>
271+
<TableCode>'Number input'</TableCode>
272+
</td>
273+
</tr>
274+
<tr>
275+
<td>
276+
<DxcFlex direction="column" gap="0.25rem" alignItems="baseline">
277+
<StatusBadge status="new" />
278+
showControls
279+
</DxcFlex>
280+
</td>
281+
<td>
282+
<TableCode>boolean</TableCode>
283+
</td>
284+
<td>
285+
Decides whether the number input has actions to increase or decrease the value, following the defined
286+
step.
287+
</td>
288+
<td>
289+
<TableCode>true</TableCode>
290+
</td>
270291
</tr>
271292
</tbody>
272293
</DxcTable>

packages/lib/src/number-input/NumberInput.stories.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const NumberInput = () => (
1515
<Title title="Without label" theme="light" level={4} />
1616
<DxcNumberInput />
1717
</ExampleContainer>
18+
<ExampleContainer>
19+
<Title title="Without controls" theme="light" level={4} />
20+
<DxcNumberInput showControls={false} />
21+
</ExampleContainer>
1822
<ExampleContainer>
1923
<Title title="With label and placeholder" theme="light" level={4} />
2024
<DxcNumberInput label="Number input" placeholder="Placeholder" />

packages/lib/src/number-input/NumberInput.test.tsx

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@ describe("Number input component tests", () => {
2424
expect(number.getAttribute("placeholder")).toBe("Placeholder");
2525
expect(queryAllByRole("button").length).toBe(2);
2626
});
27-
2827
test("Number input is disabled", () => {
2928
const { getByLabelText } = render(<DxcNumberInput label="Number label" disabled />);
3029
const number = getByLabelText("Number label") as HTMLInputElement;
3130
expect(number.disabled).toBeTruthy();
3231
});
33-
3432
test("Number input is read only and cannot be incremented or decremented using the actions", async () => {
3533
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number label" readOnly />);
3634
const number = getByLabelText("Number label") as HTMLInputElement;
@@ -42,7 +40,6 @@ describe("Number input component tests", () => {
4240
increment && (await userEvent.click(increment));
4341
expect(number.value).toBe("");
4442
});
45-
4643
test("Number input is read only and cannot be incremented or decremented using the arrow keys", () => {
4744
const { getByLabelText } = render(<DxcNumberInput label="Number label" readOnly />);
4845
const number = getByLabelText("Number label") as HTMLInputElement;
@@ -52,12 +49,10 @@ describe("Number input component tests", () => {
5249
fireEvent.keyDown(number, { keyCode: 40 });
5350
expect(number.value).toBe("");
5451
});
55-
5652
test("Number input is optional", () => {
5753
const { getByText } = render(<DxcNumberInput label="Number label" optional />);
5854
expect(getByText("(Optional)")).toBeTruthy();
5955
});
60-
6156
test("Number input is not optional: required field, displays error if not filled in", () => {
6257
const onBlur = jest.fn();
6358
const onChange = jest.fn();
@@ -73,18 +68,19 @@ describe("Number input component tests", () => {
7368
expect(onChange).toHaveBeenCalled();
7469
expect(onChange).toHaveBeenCalledWith({ value: "", error: "This field is required. Please, enter a value." });
7570
});
76-
71+
test("Hiding number input controls", () => {
72+
const { queryByRole } = render(<DxcNumberInput label="Number label" showControls={false} />);
73+
expect(queryByRole("button")).toBeFalsy();
74+
});
7775
test("Suffix and prefix must be shown", () => {
7876
const { getByText } = render(<DxcNumberInput label="Number input label" prefix="+34" suffix="USD" />);
7977
expect(getByText("+34")).toBeTruthy();
8078
expect(getByText("USD")).toBeTruthy();
8179
});
82-
8380
test("Invalid number input renders error", () => {
8481
const { getByText } = render(<DxcNumberInput error="Error message." />);
8582
expect(getByText("Error message.")).toBeTruthy();
8683
});
87-
8884
test("onChange function is called correctly", () => {
8985
const onChange = jest.fn();
9086
const { getByLabelText } = render(<DxcNumberInput label="Number input label" onChange={onChange} />);
@@ -96,7 +92,6 @@ describe("Number input component tests", () => {
9692
expect(onChange).toHaveBeenCalledWith({ value: "1" });
9793
expect(number.value).toBe("1");
9894
});
99-
10095
test("Error message is shown if the typed value is less than the min value", () => {
10196
const onChange = jest.fn(({ value, error }) => {
10297
expect(value).toBe("-1");
@@ -113,7 +108,6 @@ describe("Number input component tests", () => {
113108
userEvent.type(number, "-1");
114109
fireEvent.blur(number);
115110
});
116-
117111
test("Cannot decrement the value if it is less than the min value", async () => {
118112
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" min={5} />);
119113
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -124,7 +118,6 @@ describe("Number input component tests", () => {
124118
decrement && (await userEvent.click(decrement));
125119
expect(number.value).toBe("1");
126120
});
127-
128121
test("Increment the value when it is less than the min value", async () => {
129122
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" min={5} />);
130123
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -135,7 +128,6 @@ describe("Number input component tests", () => {
135128
increment && (await userEvent.click(increment));
136129
expect(number.value).toBe("5");
137130
});
138-
139131
test("Error message is shown if the typed value is greater than the max value", () => {
140132
const onChange = jest.fn();
141133
const onBlur = jest.fn();
@@ -150,7 +142,6 @@ describe("Number input component tests", () => {
150142
expect(onBlur).toHaveBeenCalled();
151143
expect(onBlur).toHaveBeenCalledWith({ value: "12", error: "Value must be less than or equal to 10." });
152144
});
153-
154145
test("Cannot increment the value if it is greater than the max value", async () => {
155146
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" max={10} />);
156147
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -161,7 +152,6 @@ describe("Number input component tests", () => {
161152
decrement && (await userEvent.click(decrement));
162153
expect(number.value).toBe("12");
163154
});
164-
165155
test("Decrement the value when it is greater than the max value", async () => {
166156
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" max={10} />);
167157
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -172,7 +162,6 @@ describe("Number input component tests", () => {
172162
decrement && (await userEvent.click(decrement));
173163
expect(number.value).toBe("10");
174164
});
175-
176165
test("Increment and decrement the value with min and max values", async () => {
177166
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" min={5} max={10} />);
178167
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -194,7 +183,6 @@ describe("Number input component tests", () => {
194183
increment && (await userEvent.click(increment));
195184
expect(number.value).toBe("10");
196185
});
197-
198186
test("Increment and decrement the value with an integer step", async () => {
199187
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" step={5} />);
200188
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -212,7 +200,6 @@ describe("Number input component tests", () => {
212200
decrement && (await userEvent.click(decrement));
213201
expect(number.value).toBe("10");
214202
});
215-
216203
test("Increment and decrement the value with a decimal step", async () => {
217204
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" step={0.5} />);
218205
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -232,7 +219,6 @@ describe("Number input component tests", () => {
232219
decrement && (await userEvent.click(decrement));
233220
expect(number.value).toBe("-10");
234221
});
235-
236222
test("Increment and decrement the value with min, max and step", async () => {
237223
const onBlur = jest.fn();
238224
const { getByLabelText, getAllByRole } = render(
@@ -258,7 +244,6 @@ describe("Number input component tests", () => {
258244
expect(number.value).toBe("5");
259245
decrement && (await userEvent.click(decrement));
260246
});
261-
262247
test("Start incrementing from 0 when the min value is less than 0 and the max value is bigger than 0", async () => {
263248
const onBlur = jest.fn();
264249
const { getByLabelText, getAllByRole } = render(
@@ -271,7 +256,6 @@ describe("Number input component tests", () => {
271256
increment && (await userEvent.click(increment));
272257
expect(number.value).toBe("2");
273258
});
274-
275259
test("Start incrementing from 0 when the min value is less than 0 and the max is 0", async () => {
276260
const { getByLabelText, getAllByRole } = render(
277261
<DxcNumberInput label="Number input label" min={-10} max={0} step={1} />
@@ -283,7 +267,6 @@ describe("Number input component tests", () => {
283267
increment && (await userEvent.click(increment));
284268
expect(number.value).toBe("0");
285269
});
286-
287270
test("Start incrementing from the min value when it is bigger than 0", async () => {
288271
const { getByLabelText, getAllByRole } = render(
289272
<DxcNumberInput label="Number input label" min={2} max={10} step={0.5} />
@@ -295,7 +278,6 @@ describe("Number input component tests", () => {
295278
increment && (await userEvent.click(increment));
296279
expect(number.value).toBe("2.5");
297280
});
298-
299281
test("Start incrementing from the max value when it is less than 0", async () => {
300282
const { getByLabelText, getAllByRole } = render(
301283
<DxcNumberInput label="Number input label" min={-10} max={-1} step={0.5} />
@@ -307,7 +289,6 @@ describe("Number input component tests", () => {
307289
increment && (await userEvent.click(increment));
308290
expect(number.value).toBe("-1");
309291
});
310-
311292
test("Start decrementing from 0 when the min value is less than 0 and the max value is bigger than 0", async () => {
312293
const { getByLabelText, getAllByRole } = render(
313294
<DxcNumberInput label="Number input label" min={-10} max={10} step={1} />
@@ -317,7 +298,6 @@ describe("Number input component tests", () => {
317298
decrement && (await userEvent.click(decrement));
318299
expect(number.value).toBe("-1");
319300
});
320-
321301
test("Start decrementing from 0 when the min value is 0 and the max value is bigger than 0", async () => {
322302
const { getByLabelText, getAllByRole } = render(
323303
<DxcNumberInput label="Number input label" min={0} max={10} step={1} />
@@ -327,7 +307,6 @@ describe("Number input component tests", () => {
327307
decrement && (await userEvent.click(decrement));
328308
expect(number.value).toBe("0");
329309
});
330-
331310
test("Start decrementing from the min value when it is bigger than 0", async () => {
332311
const { getByLabelText, getAllByRole } = render(
333312
<DxcNumberInput label="Number input label" min={2} max={10} step={0.5} />
@@ -339,7 +318,6 @@ describe("Number input component tests", () => {
339318
decrement && (await userEvent.click(decrement));
340319
expect(number.value).toBe("2");
341320
});
342-
343321
test("Start decrementing from the max value when it is less than 0", async () => {
344322
const { getByLabelText, getAllByRole } = render(
345323
<DxcNumberInput label="Number input label" min={-10} max={-1} step={0.5} />
@@ -351,7 +329,6 @@ describe("Number input component tests", () => {
351329
decrement && (await userEvent.click(decrement));
352330
expect(number.value).toBe("-1.5");
353331
});
354-
355332
test("Increment and decrement the value with min, max and step using the arrows in keyboard", () => {
356333
const { getByLabelText } = render(<DxcNumberInput label="Number input label" min={5} max={20} step={5} />);
357334
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -375,7 +352,6 @@ describe("Number input component tests", () => {
375352
fireEvent.keyDown(number, { keyCode: 40 });
376353
expect(number.value).toBe("5");
377354
});
378-
379355
test("Value is unchanged when using the scroll wheel in mouse in a disabled input", () => {
380356
const { getByLabelText } = render(
381357
<DxcNumberInput disabled label="Number input label" min={5} max={20} step={5} defaultValue="10" />
@@ -390,7 +366,6 @@ describe("Number input component tests", () => {
390366
fireEvent.wheel(number, { deltaY: 100 });
391367
expect(number.value).toBe("10");
392368
});
393-
394369
test("Value is unchanged when using the arrows in keyboard in a disabled input", () => {
395370
const { getByLabelText } = render(
396371
<DxcNumberInput disabled label="Number input label" min={5} max={20} step={5} defaultValue="10" />
@@ -405,7 +380,6 @@ describe("Number input component tests", () => {
405380
fireEvent.keyDown(number, { keyCode: 40 });
406381
expect(number.value).toBe("10");
407382
});
408-
409383
test("Value is unchanged when using the scroll wheel in mouse in a read-only input", () => {
410384
const { getByLabelText } = render(
411385
<DxcNumberInput readOnly label="Number input label" min={5} max={20} step={5} defaultValue="10" />
@@ -420,7 +394,6 @@ describe("Number input component tests", () => {
420394
fireEvent.wheel(number, { deltaY: 100 });
421395
expect(number.value).toBe("10");
422396
});
423-
424397
test("Value is unchanged when using the arrows in keyboard in a read-only input", () => {
425398
const { getByLabelText } = render(
426399
<DxcNumberInput readOnly label="Number input label" min={5} max={20} step={5} defaultValue="10" />
@@ -435,7 +408,6 @@ describe("Number input component tests", () => {
435408
fireEvent.keyDown(number, { keyCode: 40 });
436409
expect(number.value).toBe("10");
437410
});
438-
439411
test("Increment and decrement the value with min, max and step using the scroll wheel in mouse", () => {
440412
const { getByLabelText } = render(<DxcNumberInput label="Number input label" min={5} max={20} step={5} />);
441413
const number = getByLabelText("Number input label") as HTMLInputElement;
@@ -459,7 +431,6 @@ describe("Number input component tests", () => {
459431
fireEvent.wheel(number, { deltaY: 100 });
460432
expect(number.value).toBe("5");
461433
});
462-
463434
test("Number has correct accessibility attributes", () => {
464435
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" />);
465436
const number = getByLabelText("Number input label");
@@ -472,7 +443,6 @@ describe("Number input component tests", () => {
472443
const increment = getAllByRole("button")[1];
473444
expect(increment?.getAttribute("aria-label")).toBe("Increment value");
474445
});
475-
476446
test("Number input submits correct values inside a form and actions don't trigger the submit event", async () => {
477447
const handlerOnSubmit = jest.fn((e) => {
478448
e.preventDefault();

packages/lib/src/number-input/NumberInput.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,21 @@ const DxcNumberInput = forwardRef<RefType, NumberInputPropsType>(
2929
size,
3030
tabIndex,
3131
ariaLabel = "Number input",
32+
showControls = true,
3233
},
3334
ref
3435
) => {
3536
const numberInputRef = useRef<HTMLInputElement | null>(null);
3637

3738
const contextValue = useMemo(
3839
() => ({
39-
typeNumber: "number",
40-
minNumber: min,
4140
maxNumber: max,
41+
minNumber: min,
42+
showControls,
4243
stepNumber: step,
44+
typeNumber: "number",
4345
}),
44-
[min, max, step]
46+
[max, min, showControls, step]
4547
);
4648

4749
useEffect(() => {

packages/lib/src/number-input/types.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,18 @@ type Props = {
115115
* Specifies a string to be used as the name for the number input element when no `label` is provided.
116116
*/
117117
ariaLabel?: string;
118+
/**
119+
* Decides whether the number input has actions to increase or decrease the value, following the defined step.
120+
*/
121+
showControls?: boolean;
118122
};
119123

120124
export type NumberInputContextProps = {
125+
maxNumber: Props["max"];
126+
minNumber: Props["min"];
127+
showControls: Props["showControls"];
128+
stepNumber: Props["step"];
121129
typeNumber?: string;
122-
minNumber?: number;
123-
maxNumber?: number;
124-
stepNumber?: number;
125130
};
126131

127132
/**

0 commit comments

Comments
 (0)