Skip to content

Commit 9d1a569

Browse files
Merge pull request #533 from buildo/532-expand_fileuploaderfield
#532: Add config to FileUploaderField to customise button and allow external control of loading status
2 parents cdac5e7 + 2628bba commit 9d1a569

File tree

4 files changed

+62
-13
lines changed

4 files changed

+62
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { ButtonProps } from "..";
2+
13
export type FileUploaderFieldConfig = {
24
defaultHeight: string | number;
5+
buttonKind: ButtonProps["kind"];
36
};

packages/bento-design-system/src/FileUploaderField/FileUploaderField.tsx

+12-8
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const errorCodes = [
3434
type KnownDropzoneErrorCode = typeof errorCodes[number];
3535

3636
export type ErrorCode =
37-
| `${DropzoneErrorCode}`
37+
| `${KnownDropzoneErrorCode}`
3838
| "generic-error"
3939
| "wrong-structure"
4040
| "unable-to-read";
@@ -43,11 +43,6 @@ function isDropzoneKnownError(error: string): error is KnownDropzoneErrorCode {
4343
return errorCodes.find((c) => c === error) !== undefined;
4444
}
4545

46-
export type ErrorMessages<E extends string> = Record<
47-
E | ErrorCode,
48-
Children | ((file: File | undefined) => Children)
49-
>;
50-
5146
export type FileUploaderTexts = {
5247
title: LocalizedString;
5348
description: LocalizedString;
@@ -100,6 +95,10 @@ type Props<E extends string> = {
10095
* The field height
10196
*/
10297
height?: string | number;
98+
/**
99+
* A parameter that allows external control of the uploading status.
100+
*/
101+
isUploading?: boolean;
103102
} & Omit<FieldProps<FileResult<E> | undefined>, "assistiveText" | "issues">;
104103

105104
export type { Props as FileUploaderProps };
@@ -141,10 +140,15 @@ export function FileUploaderField<E extends string>({
141140
maxFileSize,
142141
allowedFileTypes,
143142
height: height_,
143+
isUploading,
144144
}: Props<E>) {
145145
const config = useBentoConfig().fileUploaderField;
146146
const height = height_ ?? config.defaultHeight;
147-
const [uploading, setUploading] = useState<boolean>(false);
147+
148+
const [uploading, setUploading] = useState<boolean>(isUploading ?? false);
149+
useEffect(() => {
150+
isUploading !== undefined && setUploading(isUploading);
151+
}, [isUploading]);
148152

149153
// note(Fede): useDropzone already exposes a `isDragActive` flag, but it is true
150154
// only when a file is dragged over the component, not the whole window, which is what we prefer.
@@ -340,7 +344,7 @@ export function FileUploaderField<E extends string>({
340344
</Stack>
341345
</ContentBlock>
342346
<Button
343-
kind="solid"
347+
kind={config.buttonKind}
344348
hierarchy="secondary"
345349
label={texts.uploadButtonLabel}
346350
onPress={open}

packages/bento-design-system/src/util/defaultConfigs.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ export const field: FieldConfig = {
251251

252252
export const fileUploaderField: FileUploaderFieldConfig = {
253253
defaultHeight: "8rem",
254+
buttonKind: "solid",
254255
};
255256

256257
export const inlineLoader: InlineLoaderConfig = {

packages/storybook/stories/Components/FileUploaderField.stories.tsx

+46-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { FileUploaderField } from "..";
1+
import { useState } from "react";
2+
import { StoryFn } from "@storybook/react";
3+
import { FileUploaderField, BentoConfigProvider, Button, Stack } from "..";
24
import { createComponentStories } from "../util";
35

46
const { defaultExport, createControlledStory } = createComponentStories({
@@ -8,7 +10,7 @@ const { defaultExport, createControlledStory } = createComponentStories({
810

911
export default defaultExport;
1012

11-
export const fileUploaderField = createControlledStory(undefined, {
13+
const fileUploaderProps = {
1214
label: "Upload a file",
1315
allowedFileTypes: {
1416
"text/csv": [".csv"],
@@ -21,10 +23,49 @@ export const fileUploaderField = createControlledStory(undefined, {
2123
uploadAgainMessage: "Upload another file: ",
2224
uploadingMessage: "Uploading...",
2325
uploadButtonLabel: "Choose a file",
24-
assistiveTextFileTypes: (fileTypes) =>
26+
assistiveTextFileTypes: (fileTypes?: Record<string, string[]>) =>
2527
fileTypes ? "Allowed file types: " + Object.values(fileTypes).flat().join(", ") : "",
26-
assistiveTextMaxSize: (maxSizeMb) => (maxSizeMb ? "Max file size: " + maxSizeMb + "MB" : ""),
28+
assistiveTextMaxSize: (maxSizeMb?: number) =>
29+
maxSizeMb ? "Max file size: " + maxSizeMb + "MB" : "",
2730
},
2831
renderIssue: () => "error",
2932
maxFileSize: 1000,
30-
});
33+
};
34+
35+
export const fileUploaderField = createControlledStory(undefined, fileUploaderProps);
36+
37+
export const Loading = () => {
38+
const [loading, setLoading] = useState(false);
39+
40+
return (
41+
<Stack space={16}>
42+
<FileUploaderField
43+
{...fileUploaderProps}
44+
value={undefined}
45+
onChange={() => {}}
46+
isUploading={loading}
47+
/>
48+
<Button
49+
kind="solid"
50+
hierarchy="primary"
51+
label={loading ? "Stop loading" : "Start loading"}
52+
onPress={() => setLoading(!loading)}
53+
/>
54+
</Stack>
55+
);
56+
};
57+
58+
export const withOutlineButton = createControlledStory(undefined, fileUploaderProps);
59+
withOutlineButton.decorators = [
60+
(Story: StoryFn) => (
61+
<BentoConfigProvider
62+
value={{
63+
fileUploaderField: {
64+
buttonKind: "outline",
65+
},
66+
}}
67+
>
68+
<Story />
69+
</BentoConfigProvider>
70+
),
71+
];

0 commit comments

Comments
 (0)