From 320a796827107c57c9f466c190e939d11f121e62 Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso Date: Tue, 19 Aug 2025 10:33:24 +0200 Subject: [PATCH 1/6] Add optional prop to the File Input component --- packages/lib/src/file-input/FileInput.stories.tsx | 6 ++++++ packages/lib/src/file-input/FileInput.tsx | 15 ++++++++++----- packages/lib/src/file-input/types.ts | 7 +++++++ packages/lib/src/file-input/utils.ts | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/lib/src/file-input/FileInput.stories.tsx b/packages/lib/src/file-input/FileInput.stories.tsx index 14b7c254ad..e6bff8e8c4 100644 --- a/packages/lib/src/file-input/FileInput.stories.tsx +++ b/packages/lib/src/file-input/FileInput.stories.tsx @@ -81,6 +81,12 @@ const FileInput = () => ( <DxcFileInput label="File input" value={[]} callbackFile={() => {}} /> </ExampleContainer> + + <ExampleContainer> + <Title title="Optional" theme="light" level={4} /> + <DxcFileInput label="File input" value={[]} callbackFile={() => {}} optional /> + </ExampleContainer> + <ExampleContainer> <Title title="With label and helper text" theme="light" level={4} /> <DxcFileInput label="File input" helperText="Please select files" value={[]} callbackFile={() => {}} /> diff --git a/packages/lib/src/file-input/FileInput.tsx b/packages/lib/src/file-input/FileInput.tsx index 9109460d4c..08aab3317b 100644 --- a/packages/lib/src/file-input/FileInput.tsx +++ b/packages/lib/src/file-input/FileInput.tsx @@ -105,7 +105,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( ( { mode = "file", - label = "", + label, buttonLabel, dropAreaLabel, helperText = "", @@ -119,6 +119,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( value, margin, tabIndex = 0, + optional = false, }, ref ): JSX.Element => { @@ -226,10 +227,12 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( return ( <FileInputContainer margin={margin} ref={ref}> - <Label htmlFor={fileInputId} disabled={disabled}> - {label} - </Label> - <HelperText disabled={disabled}>{helperText}</HelperText> + {label && ( + <Label disabled={disabled} hasMargin={!helperText} htmlFor={fileInputId}> + {label} {optional && <span>{translatedLabels.formFields.optionalLabel}</span>} + </Label> + )} + {helperText && <HelperText disabled={disabled}>{helperText}</HelperText>} {mode === "file" ? ( <FileContainer singleFileMode={!multiple && files.length === 1}> <ValueInput @@ -240,6 +243,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( onChange={selectFiles} disabled={disabled} readOnly + required={!optional} /> <DxcButton mode="secondary" @@ -282,6 +286,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( onChange={selectFiles} disabled={disabled} readOnly + required={!optional} /> <DragDropArea isDragging={isDragging} diff --git a/packages/lib/src/file-input/types.ts b/packages/lib/src/file-input/types.ts index ab0c39a2e5..ebe3b6cb2b 100644 --- a/packages/lib/src/file-input/types.ts +++ b/packages/lib/src/file-input/types.ts @@ -71,6 +71,13 @@ type CommonProps = { * Value of the tabindex attribute. */ tabIndex?: number; + /** + * If true, the input will be optional, showing '(Optional)' + * next to the label. Otherwise, the field will be considered required and an error will be + * passed as a parameter to the OnBlur and onChange functions when it has + * not been filled. + */ + optional?: boolean; }; type DropModeProps = CommonProps & { /** diff --git a/packages/lib/src/file-input/utils.ts b/packages/lib/src/file-input/utils.ts index 7b76761e73..cf0f4e9f40 100644 --- a/packages/lib/src/file-input/utils.ts +++ b/packages/lib/src/file-input/utils.ts @@ -24,4 +24,4 @@ export const isFileIncluded = (file: FileData, fileList: FileData[]) => { lastModified === file.file.lastModified && webkitRelativePath === file.file.webkitRelativePath ); -}; \ No newline at end of file +}; From f3d17cd98794b84d9d88ed3c245cc115cf94e170 Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso <pelayo.felgueroso@dxc.com> Date: Tue, 19 Aug 2025 14:30:43 +0200 Subject: [PATCH 2/6] Sort props on types.ts and add documentation for optional props --- .../lib/src/file-input/FileInput.stories.tsx | 1 - packages/lib/src/file-input/FileInput.tsx | 18 +++- packages/lib/src/file-input/types.ts | 84 +++++++++---------- packages/lib/src/file-input/utils.ts | 2 + 4 files changed, 61 insertions(+), 44 deletions(-) diff --git a/packages/lib/src/file-input/FileInput.stories.tsx b/packages/lib/src/file-input/FileInput.stories.tsx index e6bff8e8c4..c90a014a50 100644 --- a/packages/lib/src/file-input/FileInput.stories.tsx +++ b/packages/lib/src/file-input/FileInput.stories.tsx @@ -2,7 +2,6 @@ import { Meta, StoryObj } from "@storybook/react"; import ExampleContainer from "../../.storybook/components/ExampleContainer"; import Title from "../../.storybook/components/Title"; import DxcFileInput from "./FileInput"; -import { userEvent, within } from "@storybook/test"; export default { title: "File Input", diff --git a/packages/lib/src/file-input/FileInput.tsx b/packages/lib/src/file-input/FileInput.tsx index 08aab3317b..0baa5cbd51 100644 --- a/packages/lib/src/file-input/FileInput.tsx +++ b/packages/lib/src/file-input/FileInput.tsx @@ -5,9 +5,10 @@ import { spaces } from "../common/variables"; import FileItem from "./FileItem"; import FileInputPropsType, { FileData, RefType } from "./types"; import { HalstackLanguageContext } from "../HalstackContext"; -import { getFilePreview, isFileIncluded } from "./utils"; +import { getFilePreview, isFileIncluded, isRequired } from "./utils"; import HelperText from "../styles/forms/HelperText"; import Label from "../styles/forms/Label"; +import ErrorMessage from "../styles/forms/ErrorMessage"; const FileInputContainer = styled.div<{ margin: FileInputPropsType["margin"] }>` display: flex; @@ -124,8 +125,10 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( ref ): JSX.Element => { const [isDragging, setIsDragging] = useState(false); + const [inputError, setInputError] = useState<string | undefined>(undefined); const [files, setFiles] = useState<FileData[]>([]); const fileInputId = `file-input-${useId()}`; + const errorId = `error-${fileInputId}`; const translatedLabels = useContext(HalstackLanguageContext); const checkFileSize = (file: File) => { @@ -173,6 +176,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( const fileIndex = filesCopy.indexOf(fileToRemove); filesCopy.splice(fileIndex, 1); callbackFile?.(filesCopy); + validateIsRequired(filesCopy); } }, [files, callbackFile] @@ -207,6 +211,14 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( } }; + const validateIsRequired = (files: FileData[]) => { + if (isRequired(files, optional)) { + setInputError(translatedLabels.formFields.requiredValueErrorMessage); + } else { + setInputError(undefined); + } + }; + useEffect(() => { const getFiles = async () => { if (value) { @@ -247,6 +259,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( /> <DxcButton mode="secondary" + semantic={inputError ? "error" : "default"} label={ buttonLabel ?? (multiple @@ -299,11 +312,13 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( > <DxcButton mode="secondary" + semantic={inputError ? "error" : "default"} label={buttonLabel ?? translatedLabels.fileInput.dropAreaButtonLabelDefault} onClick={handleClick} disabled={disabled} size={{ width: "fitContent", height: "medium" }} /> + {mode === "dropzone" ? ( <DropzoneLabel disabled={disabled}> {dropAreaLabel ?? @@ -339,6 +354,7 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( )} </Container> )} + {!disabled && inputError && <ErrorMessage error={inputError} id={errorId} />} </FileInputContainer> ); } diff --git a/packages/lib/src/file-input/types.ts b/packages/lib/src/file-input/types.ts index ebe3b6cb2b..5c891e1148 100644 --- a/packages/lib/src/file-input/types.ts +++ b/packages/lib/src/file-input/types.ts @@ -1,14 +1,14 @@ import { Margin, Space } from "../common/utils"; export type FileData = { - /** - * Selected file. - */ - file: File; /** * Error of the file. If it is defined, it will be shown and the file item will be mark as invalid. */ error?: string; + /** + * Selected file. + */ + file: File; /** * Preview of the file. */ @@ -17,69 +17,73 @@ export type FileData = { type CommonProps = { /** - * Text to be placed above the component. + * The file types that the component accepts. Its value must be one of all the possible values of the HTML file input's accept attribute. */ - label?: string; + accept?: string; /** * Text to be placed inside the button. */ buttonLabel?: string; /** - * Helper text to be placed above the component. + * This function will be called when the user selects or drops a file. The list of files will be sent as a parameter. + * In this function, the files can be updated or returned as they come. These files must be passed to the value in order to be shown. */ - helperText?: string; + callbackFile: (files: FileData[]) => void; /** - * The file types that the component accepts. Its value must be one of all the possible values of the HTML file input's accept attribute. + * If true, the component will be disabled. */ - accept?: string; + disabled?: boolean; /** - * An array of files representing the selected files. + * Helper text to be placed above the component. */ - value: FileData[]; + helperText?: string; /** - * The minimum file size (in bytes) allowed. If the size of the file does not comply the minSize, the file will have an error. + * Text to be placed above the component. */ - minSize?: number; + label?: string; + /** + * Size of the margin to be applied to the component ('xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge'). + * You can pass an object with 'top', 'bottom', 'left' and 'right' properties in order to specify different margin sizes. + */ + margin?: Space | Margin; /** * The maximum file size (in bytes) allowed. If the size of the file does not comply the maxSize, the file will have an error. */ maxSize?: number; /** - * If true, if the file is an image, a preview of it will be shown. If not, an icon refering to the file type will be shown. + * The minimum file size (in bytes) allowed. If the size of the file does not comply the minSize, the file will have an error. */ - showPreview?: boolean; + minSize?: number; /** * If true, the component allows multiple file items and will show all of them. If false, only one file will be shown, and if there is already one * file selected and a new one is chosen, it will be replaced by the new selected one. */ multiple?: boolean; /** - * If true, the component will be disabled. - */ - disabled?: boolean; - /** - * This function will be called when the user selects or drops a file. The list of files will be sent as a parameter. - * In this function, the files can be updated or returned as they come. These files must be passed to the value in order to be shown. + * If true, the input will be optional, showing '(Optional)' + * next to the label. Otherwise, the field will be considered required and an error will be + * passed as a parameter to the OnBlur and onChange functions when it has + * not been filled. */ - callbackFile: (files: FileData[]) => void; + optional?: boolean; /** - * Size of the margin to be applied to the component ('xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge'). - * You can pass an object with 'top', 'bottom', 'left' and 'right' properties in order to specify different margin sizes. + * If true, if the file is an image, a preview of it will be shown. If not, an icon refering to the file type will be shown. */ - margin?: Space | Margin; + showPreview?: boolean; /** * Value of the tabindex attribute. */ tabIndex?: number; /** - * If true, the input will be optional, showing '(Optional)' - * next to the label. Otherwise, the field will be considered required and an error will be - * passed as a parameter to the OnBlur and onChange functions when it has - * not been filled. + * An array of files representing the selected files. */ - optional?: boolean; + value: FileData[]; }; type DropModeProps = CommonProps & { + /** + * Text to be placed inside the drag and drop zone alongside the button. + */ + dropAreaLabel?: string; /** * Uses one of the available file input modes: * 'file': Files are selected by clicking the button and selecting it through the file explorer. @@ -88,12 +92,12 @@ type DropModeProps = CommonProps & { * The drag and drop area of this mode is bigger than the one of the filedrop mode. */ mode: "filedrop" | "dropzone"; +}; +type FileModeProps = CommonProps & { /** * Text to be placed inside the drag and drop zone alongside the button. */ - dropAreaLabel?: string; -}; -type FileModeProps = CommonProps & { + dropAreaLabel?: never; /** * Uses one of the available file input modes: * 'file': Files are selected by clicking the button and selecting it through the file explorer. @@ -102,10 +106,6 @@ type FileModeProps = CommonProps & { * The drag and drop area of this mode is bigger than the one of the filedrop mode. */ mode?: "file"; - /** - * Text to be placed inside the drag and drop zone alongside the button. - */ - dropAreaLabel?: never; }; /** @@ -119,14 +119,14 @@ type Props = DropModeProps | FileModeProps; * Single file item preview. */ export type FileItemProps = { - fileName?: string; error?: string; + fileName?: string; + onDelete: (fileName: string) => void; + preview: string; showPreview: boolean; singleFileMode: boolean; - preview: string; - type: string; - onDelete: (fileName: string) => void; tabIndex: number; + type: string; }; export default Props; diff --git a/packages/lib/src/file-input/utils.ts b/packages/lib/src/file-input/utils.ts index cf0f4e9f40..ab3aeae9b7 100644 --- a/packages/lib/src/file-input/utils.ts +++ b/packages/lib/src/file-input/utils.ts @@ -25,3 +25,5 @@ export const isFileIncluded = (file: FileData, fileList: FileData[]) => { webkitRelativePath === file.file.webkitRelativePath ); }; + +export const isRequired = (value: FileData[], optional: boolean) => value.length === 0 && !optional; \ No newline at end of file From dd2914b54f44f014c048a3d26b111c06871815ae Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso <pelayo.felgueroso@dxc.com> Date: Wed, 20 Aug 2025 08:10:33 +0200 Subject: [PATCH 3/6] Add updated documentation page --- .../file-input/code/FileInputCodePage.tsx | 150 ++++++++++-------- 1 file changed, 82 insertions(+), 68 deletions(-) diff --git a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx index 0be192ba0d..a55128bb7c 100644 --- a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx +++ b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx @@ -24,31 +24,52 @@ const sections = [ </thead> <tbody> <tr> - <td>mode</td> + <td>accept</td> <td> - <TableCode>'file' | 'filedrop' | 'dropzone'</TableCode> + <TableCode>string</TableCode> </td> - <td>Available modes of the component.</td> <td> - <TableCode>'file'</TableCode> + The file types that the component accepts. Its value must be one of all the possible values of the HTML + file input's <Code>accept</Code> attribute. Please check the documentation{" "} + <DxcLink href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept">here</DxcLink>. </td> + <td>-</td> </tr> <tr> - <td>label</td> + <td>buttonLabel</td> <td> <TableCode>string</TableCode> </td> - <td>Text to be placed above the component.</td> + <td>Text to be placed inside the button.</td> <td>-</td> </tr> <tr> - <td>buttonLabel</td> <td> - <TableCode>string</TableCode> + <DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline"> + <StatusBadge status="required" /> + callbackFile + </DxcFlex> + </td> + <td> + <TableCode>{"(files: { file: File, error?: string, preview?: string }[]) => void"}</TableCode> + </td> + <td> + This function will be called when the user adds or deletes a file. That is, when the file input's inner + value is modified. The list of files will be sent as a parameter. In this function, the files can be + updated or returned as they come. These files must be passed to the value in order to be shown. </td> - <td>Text to be placed inside the button.</td> <td>-</td> </tr> + <tr> + <td>disabled</td> + <td> + <TableCode>boolean</TableCode> + </td> + <td>If true, the component will be disabled.</td> + <td> + <TableCode>false</TableCode> + </td> + </tr> <tr> <td>dropAreaLabel</td> <td> @@ -66,25 +87,21 @@ const sections = [ <td>-</td> </tr> <tr> - <td>accept</td> + <td>label</td> <td> <TableCode>string</TableCode> </td> - <td> - The file types that the component accepts. Its value must be one of all the possible values of the HTML - file input's <Code>accept</Code> attribute. Please check the documentation{" "} - <DxcLink href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept">here</DxcLink>. - </td> + <td>Text to be placed above the component.</td> <td>-</td> </tr> <tr> - <td>minSize</td> + <td>margin</td> <td> - <TableCode>number</TableCode> + <TableCode>'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin</TableCode> </td> <td> - The minimum file size (in bytes) allowed. If the size of the file does not comply this value, the file - will have an error. + Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and + 'right' properties in order to specify different margin sizes. </td> <td>-</td> </tr> @@ -100,43 +117,24 @@ const sections = [ <td>-</td> </tr> <tr> + <td>minSize</td> <td> - <DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline"> - <StatusBadge status="required" /> - value - </DxcFlex> - </td> - <td> - <TableCode>{"{ file: File, error?: string, preview?: string }[]"}</TableCode> + <TableCode>number</TableCode> </td> <td> - An array of files representing the selected files. Each file has the following properties: - <ul> - <li> - <b>file</b>: Selected file. - </li> - <li> - <b>error</b>: Error of the file. If it is defined, it will be shown and the file item will be mark as - invalid. - </li> - <li> - <b>preview</b>: Preview of the file. - </li> - </ul> + The minimum file size (in bytes) allowed. If the size of the file does not comply this value, the file + will have an error. </td> <td>-</td> </tr> <tr> - <td>showPreview</td> - <td> - <TableCode>boolean</TableCode> - </td> + <td>mode</td> <td> - If true, if the file is an image, a preview of it will be shown. If not, an icon referring to the file - type will be shown. + <TableCode>'file' | 'filedrop' | 'dropzone'</TableCode> </td> + <td>Available modes of the component.</td> <td> - <TableCode>false</TableCode> + <TableCode>'file'</TableCode> </td> </tr> <tr> @@ -154,42 +152,39 @@ const sections = [ </td> </tr> <tr> - <td>disabled</td> + <td>optional</td> <td> <TableCode>boolean</TableCode> </td> - <td>If true, the component will be disabled.</td> + <td> + If true, the input will be optional, showing '(Optional)' next to the label. Otherwise, the field will be + considered required and an error will be passed as a parameter to the <TableCode>onBlur</TableCode> and{" "} + <TableCode>onChange</TableCode> functions when it has not been filled. + </td> <td> <TableCode>false</TableCode> </td> </tr> <tr> + <td>ref</td> <td> - <DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline"> - <StatusBadge status="required" /> - callbackFile - </DxcFlex> - </td> - <td> - <TableCode>{"(files: { file: File, error?: string, preview?: string }[]) => void"}</TableCode> - </td> - <td> - This function will be called when the user adds or deletes a file. That is, when the file input's inner - value is modified. The list of files will be sent as a parameter. In this function, the files can be - updated or returned as they come. These files must be passed to the value in order to be shown. + <TableCode>{"React.Ref<HTMLDivElement>"}</TableCode> </td> + <td>Reference to the component.</td> <td>-</td> </tr> <tr> - <td>margin</td> + <td>showPreview</td> <td> - <TableCode>'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin</TableCode> + <TableCode>boolean</TableCode> </td> <td> - Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and - 'right' properties in order to specify different margin sizes. + If true, if the file is an image, a preview of it will be shown. If not, an icon referring to the file + type will be shown. + </td> + <td> + <TableCode>false</TableCode> </td> - <td>-</td> </tr> <tr> <td>tabIndex</td> @@ -204,11 +199,30 @@ const sections = [ </td> </tr> <tr> - <td>ref</td> <td> - <TableCode>{"React.Ref<HTMLDivElement>"}</TableCode> + <DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline"> + <StatusBadge status="required" /> + value + </DxcFlex> + </td> + <td> + <TableCode>{"{ file: File, error?: string, preview?: string }[]"}</TableCode> + </td> + <td> + An array of files representing the selected files. Each file has the following properties: + <ul> + <li> + <b>file</b>: Selected file. + </li> + <li> + <b>error</b>: Error of the file. If it is defined, it will be shown and the file item will be mark as + invalid. + </li> + <li> + <b>preview</b>: Preview of the file. + </li> + </ul> </td> - <td>Reference to the component.</td> <td>-</td> </tr> </tbody> From 40f87d5b89565bdbc3b00458e6c008b6e5ccec7d Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso <pfelguerosogalguera@gmail.com> Date: Thu, 21 Aug 2025 09:11:53 +0200 Subject: [PATCH 4/6] Remove input error from the component --- .../file-input/code/FileInputCodePage.tsx | 10 ++++------ .../lib/src/file-input/FileInput.stories.tsx | 2 -- packages/lib/src/file-input/FileInput.tsx | 16 ---------------- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx index a55128bb7c..4825913bb8 100644 --- a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx +++ b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx @@ -51,7 +51,9 @@ const sections = [ </DxcFlex> </td> <td> - <TableCode>{"(files: { file: File, error?: string, preview?: string }[]) => void"}</TableCode> + <TableCode> + {"(val: {files: { file: File, error?: string, preview?: string }[], error?: string}) => void"} + </TableCode> </td> <td> This function will be called when the user adds or deletes a file. That is, when the file input's inner @@ -156,11 +158,7 @@ const sections = [ <td> <TableCode>boolean</TableCode> </td> - <td> - If true, the input will be optional, showing '(Optional)' next to the label. Otherwise, the field will be - considered required and an error will be passed as a parameter to the <TableCode>onBlur</TableCode> and{" "} - <TableCode>onChange</TableCode> functions when it has not been filled. - </td> + <td>If true, the input will be optional, showing '(Optional)' next to the label.</td> <td> <TableCode>false</TableCode> </td> diff --git a/packages/lib/src/file-input/FileInput.stories.tsx b/packages/lib/src/file-input/FileInput.stories.tsx index c90a014a50..05d1cd72db 100644 --- a/packages/lib/src/file-input/FileInput.stories.tsx +++ b/packages/lib/src/file-input/FileInput.stories.tsx @@ -80,12 +80,10 @@ const FileInput = () => ( <Title title="With label" theme="light" level={4} /> <DxcFileInput label="File input" value={[]} callbackFile={() => {}} /> </ExampleContainer> - <ExampleContainer> <Title title="Optional" theme="light" level={4} /> <DxcFileInput label="File input" value={[]} callbackFile={() => {}} optional /> </ExampleContainer> - <ExampleContainer> <Title title="With label and helper text" theme="light" level={4} /> <DxcFileInput label="File input" helperText="Please select files" value={[]} callbackFile={() => {}} /> diff --git a/packages/lib/src/file-input/FileInput.tsx b/packages/lib/src/file-input/FileInput.tsx index 0baa5cbd51..ce2c12bf07 100644 --- a/packages/lib/src/file-input/FileInput.tsx +++ b/packages/lib/src/file-input/FileInput.tsx @@ -8,7 +8,6 @@ import { HalstackLanguageContext } from "../HalstackContext"; import { getFilePreview, isFileIncluded, isRequired } from "./utils"; import HelperText from "../styles/forms/HelperText"; import Label from "../styles/forms/Label"; -import ErrorMessage from "../styles/forms/ErrorMessage"; const FileInputContainer = styled.div<{ margin: FileInputPropsType["margin"] }>` display: flex; @@ -125,10 +124,8 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( ref ): JSX.Element => { const [isDragging, setIsDragging] = useState(false); - const [inputError, setInputError] = useState<string | undefined>(undefined); const [files, setFiles] = useState<FileData[]>([]); const fileInputId = `file-input-${useId()}`; - const errorId = `error-${fileInputId}`; const translatedLabels = useContext(HalstackLanguageContext); const checkFileSize = (file: File) => { @@ -176,7 +173,6 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( const fileIndex = filesCopy.indexOf(fileToRemove); filesCopy.splice(fileIndex, 1); callbackFile?.(filesCopy); - validateIsRequired(filesCopy); } }, [files, callbackFile] @@ -211,14 +207,6 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( } }; - const validateIsRequired = (files: FileData[]) => { - if (isRequired(files, optional)) { - setInputError(translatedLabels.formFields.requiredValueErrorMessage); - } else { - setInputError(undefined); - } - }; - useEffect(() => { const getFiles = async () => { if (value) { @@ -259,7 +247,6 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( /> <DxcButton mode="secondary" - semantic={inputError ? "error" : "default"} label={ buttonLabel ?? (multiple @@ -312,13 +299,11 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( > <DxcButton mode="secondary" - semantic={inputError ? "error" : "default"} label={buttonLabel ?? translatedLabels.fileInput.dropAreaButtonLabelDefault} onClick={handleClick} disabled={disabled} size={{ width: "fitContent", height: "medium" }} /> - {mode === "dropzone" ? ( <DropzoneLabel disabled={disabled}> {dropAreaLabel ?? @@ -354,7 +339,6 @@ const DxcFileInput = forwardRef<RefType, FileInputPropsType>( )} </Container> )} - {!disabled && inputError && <ErrorMessage error={inputError} id={errorId} />} </FileInputContainer> ); } From d91358d3ecd2bba39cbb4beb1370040a3a5b4ba0 Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso <pfelguerosogalguera@gmail.com> Date: Thu, 21 Aug 2025 11:20:39 +0200 Subject: [PATCH 5/6] Remove unnecesary function from utils.ts and its import on the component --- packages/lib/src/file-input/FileInput.tsx | 2 +- packages/lib/src/file-input/utils.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/lib/src/file-input/FileInput.tsx b/packages/lib/src/file-input/FileInput.tsx index ce2c12bf07..08aab3317b 100644 --- a/packages/lib/src/file-input/FileInput.tsx +++ b/packages/lib/src/file-input/FileInput.tsx @@ -5,7 +5,7 @@ import { spaces } from "../common/variables"; import FileItem from "./FileItem"; import FileInputPropsType, { FileData, RefType } from "./types"; import { HalstackLanguageContext } from "../HalstackContext"; -import { getFilePreview, isFileIncluded, isRequired } from "./utils"; +import { getFilePreview, isFileIncluded } from "./utils"; import HelperText from "../styles/forms/HelperText"; import Label from "../styles/forms/Label"; diff --git a/packages/lib/src/file-input/utils.ts b/packages/lib/src/file-input/utils.ts index ab3aeae9b7..cf0f4e9f40 100644 --- a/packages/lib/src/file-input/utils.ts +++ b/packages/lib/src/file-input/utils.ts @@ -25,5 +25,3 @@ export const isFileIncluded = (file: FileData, fileList: FileData[]) => { webkitRelativePath === file.file.webkitRelativePath ); }; - -export const isRequired = (value: FileData[], optional: boolean) => value.length === 0 && !optional; \ No newline at end of file From 7769e0a8d00e7ed5aca1463162891c0975e0792e Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso <pfelguerosogalguera@gmail.com> Date: Tue, 26 Aug 2025 11:24:41 +0200 Subject: [PATCH 6/6] Add new tag and fix types.ts --- .../components/file-input/code/FileInputCodePage.tsx | 7 ++++++- packages/lib/src/file-input/types.ts | 4 +--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx index 4825913bb8..28669e890a 100644 --- a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx +++ b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx @@ -154,7 +154,12 @@ const sections = [ </td> </tr> <tr> - <td>optional</td> + <td> + <DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline"> + <StatusBadge status="new" /> + optional + </DxcFlex> + </td> <td> <TableCode>boolean</TableCode> </td> diff --git a/packages/lib/src/file-input/types.ts b/packages/lib/src/file-input/types.ts index 5c891e1148..a901167918 100644 --- a/packages/lib/src/file-input/types.ts +++ b/packages/lib/src/file-input/types.ts @@ -61,9 +61,7 @@ type CommonProps = { multiple?: boolean; /** * If true, the input will be optional, showing '(Optional)' - * next to the label. Otherwise, the field will be considered required and an error will be - * passed as a parameter to the OnBlur and onChange functions when it has - * not been filled. + * next to the label. */ optional?: boolean; /**