From c1e56c9cf10b800540e09636c78eed45e9be8b29 Mon Sep 17 00:00:00 2001 From: Mil4n0r Date: Wed, 1 Oct 2025 17:21:42 +0200 Subject: [PATCH 1/5] Added select virtualization feature to Paginator --- .../src/number-input/NumberInput.stories.tsx | 52 +++++++++++++++++++ .../lib/src/paginator/Paginator.stories.tsx | 4 ++ packages/lib/src/paginator/Paginator.tsx | 1 + 3 files changed, 57 insertions(+) diff --git a/packages/lib/src/number-input/NumberInput.stories.tsx b/packages/lib/src/number-input/NumberInput.stories.tsx index 5a2024dae..4ce86475e 100644 --- a/packages/lib/src/number-input/NumberInput.stories.tsx +++ b/packages/lib/src/number-input/NumberInput.stories.tsx @@ -3,12 +3,60 @@ import ExampleContainer from "../../.storybook/components/ExampleContainer"; import Title from "../../.storybook/components/Title"; import DxcFlex from "../flex/Flex"; import DxcNumberInput from "./NumberInput"; +import { useState } from "react"; +import DxcTextInput from "../text-input/TextInput"; export default { title: "Number Input", component: DxcNumberInput, } as Meta; +// const formatNumber = (value: string | number, decimals = 2, thousandSep = ",", decimalSep = ".") => { +// if (value === "" || isNaN(Number(value))) return ""; +// const fixed = Number(value).toFixed(decimals); +// const [intPart, decPart] = fixed.split(thousandSep); +// const withThousands = intPart?.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSep) ?? ""; +// return decPart ? `${withThousands}${decimalSep}${decPart}` : withThousands; +// }; + +// const NumberInputWithFormat = () => { +// const [value, setValue] = useState(""); + +// const handleUpdate = ({ value }) => { +// setValue(value); +// const numericValue = formatNumber(value); +// console.log("NUMERICVALUE", numericValue); +// }; + +// return ; +// }; + +const formatNumber = (value: string, locale: string = "es-ES", decimals: number = 2) => { + if (value === "" || isNaN(Number(value))) return value; + const number = Number(value); + return new Intl.NumberFormat(locale, { + minimumFractionDigits: decimals, + maximumFractionDigits: decimals, + }).format(number); +}; + +const NumberInputWithFormat = () => { + const [value, setValue] = useState(""); + + const handleChange = ({ value }: { value: string }) => { + // Prevent other characters than numbers, comma, dot and minus + const filtered = value.replace(/[^0-9.,-]/g, ""); + setValue(filtered); + }; + + const handleBlur = ({ value }: { value: string }) => { + const formatted = formatNumber(value, "en-EN", 2); + setValue(formatted); + }; + + return ; +}; + const NumberInput = () => ( <> @@ -126,6 +174,10 @@ const NumberInput = () => ( + + + <NumberInputWithFormat /> + </ExampleContainer> </> ); diff --git a/packages/lib/src/paginator/Paginator.stories.tsx b/packages/lib/src/paginator/Paginator.stories.tsx index 4bf6702b3..d5d23e306 100644 --- a/packages/lib/src/paginator/Paginator.stories.tsx +++ b/packages/lib/src/paginator/Paginator.stories.tsx @@ -28,6 +28,10 @@ const Paginator = () => ( <Title title="Default with items per page options" theme="light" level={4} /> <DxcPaginator itemsPerPageOptions={[5, 10, 15]} /> </ExampleContainer> + <ExampleContainer> + <Title title="Default with items per page options virtualized" theme="light" level={4} /> + <DxcPaginator itemsPerPageOptions={Array.from({ length: 10000 }, (_, i) => i + 1)} /> + </ExampleContainer> <ExampleContainer> <Title title="Default with show go to page selector" theme="light" level={4} /> <DxcPaginator showGoToPage /> diff --git a/packages/lib/src/paginator/Paginator.tsx b/packages/lib/src/paginator/Paginator.tsx index 28fdba864..c691a766c 100644 --- a/packages/lib/src/paginator/Paginator.tsx +++ b/packages/lib/src/paginator/Paginator.tsx @@ -102,6 +102,7 @@ const DxcPaginator = ({ value={itemsPerPage.toString()} size="fillParent" tabIndex={tabIndex} + virtualizedHeight={itemsPerPageOptions.length >= 100 ? "304px" : undefined} /> </SelectContainer> </ItemsPerPageContainer> From 7f135b8a9fb1ed69442557f1829ff50520872c9e Mon Sep 17 00:00:00 2001 From: Mil4n0r <morenocarmonaenrique@gmail.com> Date: Thu, 2 Oct 2025 08:06:58 +0200 Subject: [PATCH 2/5] Added documentation details in paginator --- .../screens/components/paginator/code/PaginatorCodePage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/website/screens/components/paginator/code/PaginatorCodePage.tsx b/apps/website/screens/components/paginator/code/PaginatorCodePage.tsx index 08f101c51..9ffcfacbb 100644 --- a/apps/website/screens/components/paginator/code/PaginatorCodePage.tsx +++ b/apps/website/screens/components/paginator/code/PaginatorCodePage.tsx @@ -46,7 +46,8 @@ const sections = [ </td> <td> An array of numbers representing the items per page options. If undefined, the select with items per page - options will not be displayed. + options will not be displayed. If there are 100 or more options, the select will be virtualized for better + performance. </td> <td>-</td> </tr> From 2a147775fe8409241b8c2e33393d044c7e559f20 Mon Sep 17 00:00:00 2001 From: Mil4n0r <morenocarmonaenrique@gmail.com> Date: Thu, 2 Oct 2025 08:14:28 +0200 Subject: [PATCH 3/5] Added virtualization interaction test to paginator --- packages/lib/src/paginator/Paginator.stories.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/lib/src/paginator/Paginator.stories.tsx b/packages/lib/src/paginator/Paginator.stories.tsx index d5d23e306..3197462c5 100644 --- a/packages/lib/src/paginator/Paginator.stories.tsx +++ b/packages/lib/src/paginator/Paginator.stories.tsx @@ -2,6 +2,7 @@ import { Meta, StoryObj } from "@storybook/react"; import ExampleContainer from "../../.storybook/components/ExampleContainer"; import Title from "../../.storybook/components/Title"; import DxcPaginator from "./Paginator"; +import { userEvent, within } from "@storybook/test"; export default { title: "Paginator", @@ -80,6 +81,13 @@ type Story = StoryObj<typeof DxcPaginator>; export const Chromatic: Story = { render: Paginator, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const virtualizedSelect = canvas.getAllByRole("combobox")[1]; + if (virtualizedSelect) { + await userEvent.click(virtualizedSelect); + } + }, }; export const ResponsivePaginator: Story = { From 9789779bbf644383a31cc7e84d108500157d015f Mon Sep 17 00:00:00 2001 From: Mil4n0r <morenocarmonaenrique@gmail.com> Date: Thu, 2 Oct 2025 08:22:52 +0200 Subject: [PATCH 4/5] Removed code from another task --- .../src/number-input/NumberInput.stories.tsx | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/packages/lib/src/number-input/NumberInput.stories.tsx b/packages/lib/src/number-input/NumberInput.stories.tsx index 4ce86475e..5a2024dae 100644 --- a/packages/lib/src/number-input/NumberInput.stories.tsx +++ b/packages/lib/src/number-input/NumberInput.stories.tsx @@ -3,60 +3,12 @@ import ExampleContainer from "../../.storybook/components/ExampleContainer"; import Title from "../../.storybook/components/Title"; import DxcFlex from "../flex/Flex"; import DxcNumberInput from "./NumberInput"; -import { useState } from "react"; -import DxcTextInput from "../text-input/TextInput"; export default { title: "Number Input", component: DxcNumberInput, } as Meta<typeof DxcNumberInput>; -// const formatNumber = (value: string | number, decimals = 2, thousandSep = ",", decimalSep = ".") => { -// if (value === "" || isNaN(Number(value))) return ""; -// const fixed = Number(value).toFixed(decimals); -// const [intPart, decPart] = fixed.split(thousandSep); -// const withThousands = intPart?.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSep) ?? ""; -// return decPart ? `${withThousands}${decimalSep}${decPart}` : withThousands; -// }; - -// const NumberInputWithFormat = () => { -// const [value, setValue] = useState(""); - -// const handleUpdate = ({ value }) => { -// setValue(value); -// const numericValue = formatNumber(value); -// console.log("NUMERICVALUE", numericValue); -// }; - -// return <DxcNumberInput label="Importe" value={value} onChange={handleUpdate} onBlur={handleUpdate} />; -// }; - -const formatNumber = (value: string, locale: string = "es-ES", decimals: number = 2) => { - if (value === "" || isNaN(Number(value))) return value; - const number = Number(value); - return new Intl.NumberFormat(locale, { - minimumFractionDigits: decimals, - maximumFractionDigits: decimals, - }).format(number); -}; - -const NumberInputWithFormat = () => { - const [value, setValue] = useState(""); - - const handleChange = ({ value }: { value: string }) => { - // Prevent other characters than numbers, comma, dot and minus - const filtered = value.replace(/[^0-9.,-]/g, ""); - setValue(filtered); - }; - - const handleBlur = ({ value }: { value: string }) => { - const formatted = formatNumber(value, "en-EN", 2); - setValue(formatted); - }; - - return <DxcTextInput pattern="^[0-9.,-]*$" value={value} onChange={handleChange} onBlur={handleBlur} prefix="$" />; -}; - const NumberInput = () => ( <> <ExampleContainer> @@ -174,10 +126,6 @@ const NumberInput = () => ( <DxcNumberInput label="large" size="large" /> </DxcFlex> </ExampleContainer> - <ExampleContainer> - <Title title="Amount" theme="light" level={4} /> - <NumberInputWithFormat /> - </ExampleContainer> </> ); From 94b5a769ca6541430e721b5532a70f8b61a410a0 Mon Sep 17 00:00:00 2001 From: Mil4n0r <morenocarmonaenrique@gmail.com> Date: Thu, 2 Oct 2025 08:43:51 +0200 Subject: [PATCH 5/5] Added interaction to responsive story --- packages/lib/src/paginator/Paginator.stories.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/lib/src/paginator/Paginator.stories.tsx b/packages/lib/src/paginator/Paginator.stories.tsx index 3197462c5..ec0a6f551 100644 --- a/packages/lib/src/paginator/Paginator.stories.tsx +++ b/packages/lib/src/paginator/Paginator.stories.tsx @@ -96,4 +96,11 @@ export const ResponsivePaginator: Story = { viewport: { viewports: customViewports, defaultViewport: "resizedScreen" }, chromatic: { viewports: [400] }, }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const virtualizedSelect = canvas.getAllByRole("combobox")[1]; + if (virtualizedSelect) { + await userEvent.click(virtualizedSelect); + } + }, };