diff --git a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx index 0be192ba0..28669e890 100644 --- a/apps/website/screens/components/file-input/code/FileInputCodePage.tsx +++ b/apps/website/screens/components/file-input/code/FileInputCodePage.tsx @@ -24,31 +24,54 @@ const sections = [ - mode + accept - 'file' | 'filedrop' | 'dropzone' + string - Available modes of the component. - 'file' + 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. Please check the documentation{" "} + here. + - - label + buttonLabel string - Text to be placed above the component. + Text to be placed inside the button. - - buttonLabel - string + + + callbackFile + + + + + {"(val: {files: { file: File, error?: string, preview?: string }[], error?: string}) => void"} + + + + 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. - Text to be placed inside the button. - + + disabled + + boolean + + If true, the component will be disabled. + + false + + dropAreaLabel @@ -66,25 +89,21 @@ const sections = [ - - accept + label string - - 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. Please check the documentation{" "} - here. - + Text to be placed above the component. - - minSize + margin - number + 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin - 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. - @@ -100,43 +119,24 @@ const sections = [ - + minSize - - - value - - - - {"{ file: File, error?: string, preview?: string }[]"} + number - An array of files representing the selected files. Each file has the following properties: - + The minimum file size (in bytes) allowed. If the size of the file does not comply this value, the file + will have an error. - - showPreview - - boolean - + mode - 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. + 'file' | 'filedrop' | 'dropzone' + Available modes of the component. - false + 'file' @@ -154,42 +154,40 @@ const sections = [ - disabled + + + + optional + + boolean - If true, the component will be disabled. + If true, the input will be optional, showing '(Optional)' next to the label. false + ref - - - callbackFile - - - - {"(files: { file: File, error?: string, preview?: string }[]) => void"} - - - 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. + {"React.Ref"} + Reference to the component. - - margin + showPreview - 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin + boolean - 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. + + + false - - tabIndex @@ -204,11 +202,30 @@ const sections = [ - ref - {"React.Ref"} + + + value + + + + {"{ file: File, error?: string, preview?: string }[]"} + + + An array of files representing the selected files. Each file has the following properties: + - Reference to the component. - diff --git a/packages/lib/src/file-input/FileInput.stories.tsx b/packages/lib/src/file-input/FileInput.stories.tsx index 14b7c254a..05d1cd72d 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", @@ -81,6 +80,10 @@ 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 9109460d4..08aab3317 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 ab0c39a2e..a90116791 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,62 +17,71 @@ 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. */ - 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; + /** + * An array of files representing the selected files. + */ + 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. @@ -81,12 +90,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. @@ -95,10 +104,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; }; /** @@ -112,14 +117,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 7b76761e7..cf0f4e9f4 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 +};