Skip to content

Commit

Permalink
feat(FileUpload): add helpText to FileUpload (#302)
Browse files Browse the repository at this point in the history
* docs(TimePicker): add Help Text story

* feat(FileUpload): add helpText prop to file upload

* docs(FileUpload): add helpText to size stories

* linter errors

* conditional help text

* remove box childGap for null childrewn

Co-authored-by: Juan Fabrega <[email protected]>
  • Loading branch information
nathanyoung and juanfabrega authored Oct 27, 2020
1 parent 3429433 commit 726aa20
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 106 deletions.
16 changes: 10 additions & 6 deletions src/components/Box/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,9 @@ const Box: FC<BoxProps> = ({
* Shallow merges existing classes of child node with a className based on the childGap value.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const decorateChildren = (child: ReactElement<any>, i: number) => {
const decorateChildren = (child: string | number | ReactElement<any>, i: number, array: ReactElement<any>[]) => {
if (
i === Children.count(children) - 1
i === array.length - 1
|| !child
|| typeof child === 'string'
|| typeof child === 'number'
Expand All @@ -352,11 +352,15 @@ const Box: FC<BoxProps> = ({
});
};

let decoratedChildren = Children.map(children, child => child);
let decoratedChildren = Children.toArray(children).filter(child => child !== null);

if (childGapClasses && Children.count(children) > 1) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
decoratedChildren = Children.map(children as ReactElement<any>[], decorateChildren);
if (childGapClasses && decoratedChildren.length > 1) {
decoratedChildren = decoratedChildren
.map((value, index, array) => decorateChildren(
value as string | number | ReactElement<any>, // eslint-disable-line @typescript-eslint/no-explicit-any
index,
array as ReactElement<any>[], // eslint-disable-line @typescript-eslint/no-explicit-any
));
}

const element = getElementType(Box, { as });
Expand Down
134 changes: 86 additions & 48 deletions src/components/FileUpload/FileUpload.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import Heading from '../Heading/Heading';
import Box from '../Box/Box';
import Button from '../Button/Button';

<Meta
title="Components/Form Inputs/FileUpload"
component={FileUpload}
/>
<Meta title="Components/Form Inputs/FileUpload" component={FileUpload} />

# File Upload

Expand All @@ -27,35 +24,57 @@ Use File Upload to capture file uploads in forms or elsewhere.
<Story name="Default">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return <FileUpload labelText="My File" id="myFile" onChange={handleChange} files={files} />;
}}
</Story>
</Canvas>

## Custom Button Text

You can pass down custom text to be displayed in the button

<Canvas>
<Story name="Button text">
{() => {
const [files, setFiles] = useState(null);
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
id="myFile"
onChange={handleChange}
files={files}
buttonText="Upload Your Power Bill"
/>
);
}}
</Story>
</Canvas>

## Custom Button Text
## Help Text

You can pass down custom text to be displayed in the button
Use the `helpText` prop to add clarifying text adjacent to the file upload button.

<Canvas>
<Story name="Button text">
<Story name="Help Text">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
id="myFile"
onChange={handleChange}
files={files}
buttonText="Upload Your Power Bill"
helpText="image files only (jpg, png, gif)"
accept="image/*"
/>
);
}}
Expand All @@ -70,7 +89,9 @@ Remove the icon on the button with the handy `hasIcon` boolean.
<Story name="No Icon">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
Expand Down Expand Up @@ -101,34 +122,41 @@ some specific variations have been removed, providing a stricter subset for usag
{ label: 'Light (default)', value: 'light' },
{ label: 'Dark', value: 'dark' },
];
const handleChange = (event) => { alert(`You picked this file: ${event.target.files[0].name}`) };
const handleChange = event => {
alert(`You picked this file: ${event.target.files[0].name}`);
};
return (
<Box childGap="sm">
<Heading size="md">Sizes</Heading>
<Box direction="row" childGap="sm">
{sizes.map(size => (
<FileUpload
key={size.label}
labelText={size.label}
id={size.label}
onChange={handleChange}
size={size.value}
buttonText={size.label}
/>
))}
<Box childGap="lg" direction="row">
<Box childGap="sm">
<Heading size="md">Sizes</Heading>
<Box childGap="sm">
{sizes.map(size => (
<FileUpload
key={size.label}
labelText={size.label}
id={size.label}
onChange={handleChange}
size={size.value}
buttonText={size.label}
helpText="helpful text"
/>
))}
</Box>
</Box>
<Heading size="md">Colors</Heading>
<Box direction="row" childGap="sm">
{colors.map(color => (
<FileUpload
key={color.label}
labelText={color.label}
id={color.label}
onChange={handleChange}
variant={color.value}
buttonText={color.label}
/>
))}
<Box childGap="sm">
<Heading size="md">Colors</Heading>
<Box childGap="sm">
{colors.map(color => (
<FileUpload
key={color.label}
labelText={color.label}
id={color.label}
onChange={handleChange}
variant={color.value}
buttonText={color.label}
/>
))}
</Box>
</Box>
</Box>
);
Expand All @@ -139,19 +167,19 @@ some specific variations have been removed, providing a stricter subset for usag
## Clearing Files

Pass a callback function `onClearFiles` to handle the click event for clearing all files from the input.
NOTE: since this is a controlled input, the callback itself will not clear any files, it is expected that
NOTE: since this is a controlled input, the callback itself will not clear any files, it is expected that
they are cleared at the top level where the `files` prop is emptied.

<Canvas>
<Story name="Clear">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => {
const handleChange = event => {
setFiles(event.target.files);
};
const handleClear = (event) => {
const handleClear = event => {
setFiles(null);
}
};
return (
<Box childGap="md" direction="row">
<FileUpload
Expand All @@ -177,7 +205,9 @@ window in one go, if they simply click the button numerous times, the file input
<Story name="Multiple Files">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
Expand All @@ -203,7 +233,9 @@ The example below only accepts image files.
<Story name="File Types">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
Expand All @@ -229,7 +261,9 @@ To accomplish this we simply truncate excess characters in the middle of the fil
<Story name="Truncated File Names">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
Expand All @@ -251,7 +285,9 @@ Pass the `fullWidth` prop to have your FileUpload button take up the entire widt
<Story name="Full Width">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
Expand All @@ -273,7 +309,9 @@ Pass the `isDisabled` prop to render a disabled FileUpload.
<Story name="Disabled">
{() => {
const [files, setFiles] = useState(null);
const handleChange = (event) => { setFiles(event.target.files) };
const handleChange = event => {
setFiles(event.target.files);
};
return (
<FileUpload
labelText="My File"
Expand All @@ -297,13 +335,13 @@ display a proper error when necessary.
{() => {
const [files, setFiles] = useState(null);
const [error, setError] = useState(null);
const handleChange = (event) => {
const handleChange = event => {
setFiles(event.target.files);
if (event.target.files.length > 0) {
setError(null);
}
};
const handleSubmit = (event) => {
const handleSubmit = event => {
if (!files || files.length === 0) {
setError('This field is required');
} else {
Expand Down
Loading

0 comments on commit 726aa20

Please sign in to comment.