diff --git a/documentation-site/cheat-sheet.jsx b/documentation-site/cheat-sheet.jsx index 5949c34023..b44bd0b2f0 100644 --- a/documentation-site/cheat-sheet.jsx +++ b/documentation-site/cheat-sheet.jsx @@ -1438,6 +1438,63 @@ const outlines = [ }, { file: "src/file-uploader/types.ts", + definitions: [ + { + name: "StyleProps", + lineStart: 15, + children: [ + { name: "$alt", lineStart: 16 }, + { name: "$color", lineStart: 17 }, + { name: "$fileCount", lineStart: 18 }, + { name: "$src", lineStart: 19 }, + ], + }, + { + name: "FileUploaderOverrides", + lineStart: 22, + children: [ + { name: "CircleCheckFilledIcon", lineStart: 23 }, + { name: "CircleExclamationPointFilledIcon", lineStart: 24 }, + { name: "DeleteButtonComponent", lineStart: 25 }, + { name: "FileRow", lineStart: 26 }, + { name: "FileRowColumn", lineStart: 27 }, + { name: "FileRowContent", lineStart: 28 }, + { name: "FileRowFileName", lineStart: 29 }, + { name: "FileRowText", lineStart: 30 }, + { name: "FileRowUploadMessage", lineStart: 31 }, + { name: "FileRowUploadText", lineStart: 32 }, + { name: "FileRows", lineStart: 33 }, + { name: "Hint", lineStart: 34 }, + { name: "ImagePreviewThumbnail", lineStart: 35 }, + { name: "ItemPreviewContainer", lineStart: 36 }, + { name: "Label", lineStart: 37 }, + { name: "PaperclipFilledIcon", lineStart: 38 }, + { name: "ParentRoot", lineStart: 39 }, + { name: "TrashCanFilledIcon", lineStart: 40 }, + ], + }, + { name: "FileRow", lineStart: 43, children: [ + { name: "errorMessage", lineStart: 44 }, + { name: "file", lineStart: 45 }, + { name: "id", lineStart: 46 }, + { name: "fileInfo", lineStart: 49 }, + { name: "imagePreviewThumbnail", lineStart: 50 }, + { name: "status", lineStart: 52 }, + ] }, + { name: "FileUploaderProps", lineStart: 55, children: [ + { name: "fileRows", lineStart: 59 }, + { name: "hint", lineStart: 60 }, + { name: "itemPreview", lineStart: 61 }, + { name: "label", lineStart: 62 }, + { name: "maxFiles", lineStart: 63 }, + { name: "overrides", lineStart: 64 }, + { name: "processFileOnDrop", lineStart: 66 }, + { name: "setFileRows", lineStart: 67 }, + ] }, + ], + }, + { + file: "src/file-uploader-basic/types.ts", definitions: [ { name: "StyleProps", @@ -1452,7 +1509,7 @@ const outlines = [ ], }, { - name: "FileUploaderOverrides", + name: "FileUploaderBasicOverrides", lineStart: 20, children: [ { name: "Root", lineStart: 21 }, @@ -1469,64 +1526,8 @@ const outlines = [ { name: "ProgressBar", lineStart: 32 }, ], }, - { name: "FileUploaderProps", lineStart: 35, children: [] }, - { name: "DropFilesEventHandler", lineStart: 48, children: [] }, - ], - }, - { - file: "src/file-uploader-beta/types.ts", - definitions: [ - { - name: "StyleProps", - lineStart: 15, - children: [ - { name: "$alt", lineStart: 16 }, - { name: "$color", lineStart: 17 }, - { name: "$fileCount", lineStart: 18 }, - { name: "$src", lineStart: 19 }, - ], - }, - { - name: "FileUploaderBetaOverrides", - lineStart: 22, - children: [ - { name: "AlertIcon", lineStart: 23 }, - { name: "CircleCheckFilledIcon", lineStart: 24 }, - { name: "FileRow", lineStart: 25 }, - { name: "FileRowColumn", lineStart: 26 }, - { name: "FileRowContent", lineStart: 27 }, - { name: "FileRowFileName", lineStart: 28 }, - { name: "FileRowText", lineStart: 29 }, - { name: "FileRowUploadMessage", lineStart: 30 }, - { name: "FileRowUploadText", lineStart: 31 }, - { name: "FileRows", lineStart: 32 }, - { name: "Hint", lineStart: 33 }, - { name: "ImagePreviewThumbnail", lineStart: 34 }, - { name: "ItemPreviewContainer", lineStart: 35 }, - { name: "Label", lineStart: 36 }, - { name: "PaperclipFilledIcon", lineStart: 37 }, - { name: "ParentRoot", lineStart: 38 }, - { name: "TrashCanFilledIcon", lineStart: 39 }, - { name: "TrashCanFilledIconContainer", lineStart: 40 }, - ], - }, - { name: "FileRow", lineStart: 43, children: [ - { name: "errorMessage", lineStart: 44 }, - { name: "file", lineStart: 45 }, - { name: "fileInfo", lineStart: 48 }, - { name: "imagePreviewThumbnail", lineStart: 49 }, - { name: "status", lineStart: 51 }, - ] }, - { name: "FileUploaderBetaProps", lineStart: 54, children: [ - { name: "fileRows", lineStart: 58 }, - { name: "hint", lineStart: 59 }, - { name: "itemPreview", lineStart: 60 }, - { name: "label", lineStart: 61 }, - { name: "maxFiles", lineStart: 62 }, - { name: "overrides", lineStart: 63 }, - { name: "processFileOnDrop", lineStart: 65 }, - { name: "setFileRows", lineStart: 66 }, - ] }, + { name: "FileUploaderBasicProps", lineStart: 35, children: [] }, + { name: "DropFilesEventHandler", lineStart: 52, children: [] }, ], }, { @@ -2124,18 +2125,19 @@ const outlines = [ name: "Locale", lineStart: 20, children: [ - { name: "accordion", lineStart: 21 }, - { name: "breadcrumbs", lineStart: 22 }, - { name: "datepicker", lineStart: 23 }, - { name: "datatable", lineStart: 24 }, - { name: "buttongroup", lineStart: 25 }, - { name: "fileuploader", lineStart: 26 }, - { name: "menu", lineStart: 27 }, - { name: "modal", lineStart: 28 }, - { name: "drawer", lineStart: 29 }, - { name: "pagination", lineStart: 30 }, - { name: "select", lineStart: 31 }, - { name: "toast", lineStart: 32 }, + { name: "accordion", lineStart: 22 }, + { name: "breadcrumbs", lineStart: 23 }, + { name: "datepicker", lineStart: 24 }, + { name: "datatable", lineStart: 25 }, + { name: "buttongroup", lineStart: 26 }, + { name: "fileuploader", lineStart: 27 }, + { name: "fileuploaderbasic", lineStart: 28 }, + { name: "menu", lineStart: 29 }, + { name: "modal", lineStart: 30 }, + { name: "drawer", lineStart: 31 }, + { name: "pagination", lineStart: 32 }, + { name: "select", lineStart: 33 }, + { name: "toast", lineStart: 34 }, ], }, ], diff --git a/documentation-site/components/gallery.jsx b/documentation-site/components/gallery.jsx index 574c0bfc88..9acf7721f6 100644 --- a/documentation-site/components/gallery.jsx +++ b/documentation-site/components/gallery.jsx @@ -66,8 +66,8 @@ const COMPONENTS = { Component: thumbnails.SvgFileUploader, }, { - href: "/components/file-uploader-beta", - Component: thumbnails.SvgFileUploaderBeta, + href: "/components/file-uploader-basic", + Component: thumbnails.SvgFileUploaderBasic, }, { href: "/components/menu", diff --git a/documentation-site/components/thumbs/components/FileUploaderBeta.jsx b/documentation-site/components/thumbs/components/FileUploaderBasic.jsx similarity index 92% rename from documentation-site/components/thumbs/components/FileUploaderBeta.jsx rename to documentation-site/components/thumbs/components/FileUploaderBasic.jsx index d2db519356..3c9bceadf3 100644 --- a/documentation-site/components/thumbs/components/FileUploaderBeta.jsx +++ b/documentation-site/components/thumbs/components/FileUploaderBasic.jsx @@ -8,7 +8,7 @@ LICENSE file in the root directory of this source tree. import React from "react"; -export default function SvgFileUploaderBeta(props) { +export default function SvgFileUploaderBasic(props) { return ( diff --git a/documentation-site/components/thumbs/index.jsx b/documentation-site/components/thumbs/index.jsx index db448b3d23..9268bb2b26 100644 --- a/documentation-site/components/thumbs/index.jsx +++ b/documentation-site/components/thumbs/index.jsx @@ -21,7 +21,7 @@ export { default as SvgTextarea } from "./components/Textarea.jsx"; // Pickers export { default as SvgFileUploader } from "./components/FileUploader.jsx"; -export { default as SvgFileUploaderBeta } from "./components/FileUploader.jsx"; +export { default as SvgFileUploaderBasic } from "./components/FileUploaderBasic.jsx"; export { default as SvgMenu } from "./components/Menu.jsx"; export { default as SvgRating } from "./components/Rating.jsx"; export { default as SvgSelect } from "./components/Select.jsx"; diff --git a/documentation-site/components/yard/config/file-uploader-beta.ts b/documentation-site/components/yard/config/file-uploader-basic.ts similarity index 52% rename from documentation-site/components/yard/config/file-uploader-beta.ts rename to documentation-site/components/yard/config/file-uploader-basic.ts index 27026e3da7..611ee21c54 100644 --- a/documentation-site/components/yard/config/file-uploader-beta.ts +++ b/documentation-site/components/yard/config/file-uploader-basic.ts @@ -5,10 +5,10 @@ This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. */ -import { FileUploaderBeta } from "baseui/file-uploader-beta"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; import { PropTypes } from "react-view"; import type { TConfig } from "../types"; -import iconConfig from "./icon"; +import buttonConfig from "./button"; const changeHandlers = [ "onClick", @@ -19,18 +19,21 @@ const changeHandlers = [ "onDragEnter", "onDragOver", "onDragLeave", + "onDrop", + "onDropAccepted", + "onDropRejected", "onFileDialogCancel", "onCancel", "onRetry", ]; -const FileUploaderBetaConfig: TConfig = { - componentName: "FileUploaderBeta", +const FileUploaderBasicConfig: TConfig = { + componentName: "FileUploaderBasic", imports: { - "baseui/file-uploader-beta": { named: ["FileUploaderBeta"] }, + "baseui/file-uploader-basic": { named: ["FileUploaderBasic"] }, }, scope: { - FileUploaderBeta, + FileUploaderBasic: FileUploaderBasic, }, theme: [], props: { @@ -40,38 +43,6 @@ const FileUploaderBetaConfig: TConfig = { description: "Set accepted file types. See https://github.com/okonet/attr-accept for more information", }, - disabled: { - value: false, - type: PropTypes.Boolean, - description: "Renders component in disabled state.", - }, - fileRows: { - value: "[]", - type: PropTypes.Array, - description: "Array of file objects.", - stateful: true, - }, - hint: { - value: undefined, - type: PropTypes.String, - description: "Hint text to be displayed below the file rows.", - }, - itemPreview: { - value: false, - type: PropTypes.Boolean, - description: - "Renders a file preview thumbnail. Works best with image files.", - }, - label: { - value: undefined, - type: PropTypes.String, - description: "Label text to be displayed above the file uploader.", - }, - maxFiles: { - value: undefined, - type: PropTypes.Number, - description: "Maximum number of files that can be uploaded.", - }, maxSize: { value: undefined, type: PropTypes.Number, @@ -82,36 +53,28 @@ const FileUploaderBetaConfig: TConfig = { type: PropTypes.Number, description: "Minimum file size (in bytes).", }, - processFileOnDrop: { - value: undefined, - type: PropTypes.Function, - description: - "Application defined callback function that runs on file drop. Takes a File as input and returns a Promise<{ errorMessage: string | null; fileInfo?: any }>.", - }, - setFileRows: { - value: "newFileRows => setFileRows(newFileRows)", - type: PropTypes.Function, - description: "Function to set file rows.", - }, multiple: { value: undefined, type: PropTypes.Boolean, description: "Allow drag n drop (or selection from the file dialog) of multiple files", - hidden: true, }, disableClick: { value: undefined, type: PropTypes.Boolean, description: "Disallow clicking on the dropzone container to open file dialog.", - hidden: true, + }, + disabled: { + value: false, + type: PropTypes.Boolean, + description: "Renders component in disabled state.", }, errorMessage: { - value: undefined, + value: "", type: PropTypes.String, description: "Error message to be displayed.", - hidden: true, + stateful: true, }, ...changeHandlers.reduce((acc, current) => { //@ts-ignore @@ -141,24 +104,15 @@ const FileUploaderBetaConfig: TConfig = { description: "Lets you customize all aspects of the component.", custom: { names: [ - { ...iconConfig, componentName: "AlertIcon" }, - { ...iconConfig, componentName: "CircleCheckFilledIcon" }, - "FileRow", - "FileRowColumn", - "FileRowContent", - "FileRowFileName", - "FileRowText", - "FileRowUploadMessage", - "FileRowUploadText", - "FileRows", - "Hint", - "ImagePreviewThumbnail", - "ItemPreviewContainer", - "Label", - { ...iconConfig, componentName: "PaperclipFilledIcon" }, - "ParentRoot", - { ...iconConfig, componentName: "TrashCanFilledIcon" }, - "TrashCanFilledIconContainer", + { ...buttonConfig, componentName: "ButtonComponent" }, + { ...buttonConfig, componentName: "CancelButtonComponent" }, + { ...buttonConfig, componentName: "RetryButtonComponent" }, + "ContentMessage", + "ErrorMessage", + "FileDragAndDrop", + "HiddenInput", + "Spinner", + "ProgressBar", ], sharedProps: {}, }, @@ -166,4 +120,4 @@ const FileUploaderBetaConfig: TConfig = { }, }; -export default FileUploaderBetaConfig; +export default FileUploaderBasicConfig; diff --git a/documentation-site/components/yard/config/file-uploader.ts b/documentation-site/components/yard/config/file-uploader.ts index 04647d5f4a..778941bb13 100644 --- a/documentation-site/components/yard/config/file-uploader.ts +++ b/documentation-site/components/yard/config/file-uploader.ts @@ -8,7 +8,7 @@ LICENSE file in the root directory of this source tree. import { FileUploader } from "baseui/file-uploader"; import { PropTypes } from "react-view"; import type { TConfig } from "../types"; -import buttonConfig from "./button"; +import iconConfig from "./icon"; const changeHandlers = [ "onClick", @@ -19,9 +19,6 @@ const changeHandlers = [ "onDragEnter", "onDragOver", "onDragLeave", - "onDrop", - "onDropAccepted", - "onDropRejected", "onFileDialogCancel", "onCancel", "onRetry", @@ -33,7 +30,7 @@ const FileUploaderConfig: TConfig = { "baseui/file-uploader": { named: ["FileUploader"] }, }, scope: { - FileUploader, + FileUploader: FileUploader, }, theme: [], props: { @@ -43,6 +40,38 @@ const FileUploaderConfig: TConfig = { description: "Set accepted file types. See https://github.com/okonet/attr-accept for more information", }, + disabled: { + value: false, + type: PropTypes.Boolean, + description: "Renders component in disabled state.", + }, + fileRows: { + value: "[]", + type: PropTypes.Array, + description: "Array of file objects.", + stateful: true, + }, + hint: { + value: undefined, + type: PropTypes.String, + description: "Hint text to be displayed below the file rows.", + }, + itemPreview: { + value: false, + type: PropTypes.Boolean, + description: + "Renders a file preview thumbnail. Works best with image files.", + }, + label: { + value: undefined, + type: PropTypes.String, + description: "Label text to be displayed above the file uploader.", + }, + maxFiles: { + value: undefined, + type: PropTypes.Number, + description: "Maximum number of files that can be uploaded.", + }, maxSize: { value: undefined, type: PropTypes.Number, @@ -53,28 +82,36 @@ const FileUploaderConfig: TConfig = { type: PropTypes.Number, description: "Minimum file size (in bytes).", }, + processFileOnDrop: { + value: undefined, + type: PropTypes.Function, + description: + "Application defined callback function that runs on file drop. Takes a File as input and returns a Promise<{ errorMessage: string | null; fileInfo?: any }>.", + }, + setFileRows: { + value: "newFileRows => setFileRows(newFileRows)", + type: PropTypes.Function, + description: "Function to set file rows.", + }, multiple: { value: undefined, type: PropTypes.Boolean, description: "Allow drag n drop (or selection from the file dialog) of multiple files", + hidden: true, }, disableClick: { value: undefined, type: PropTypes.Boolean, description: "Disallow clicking on the dropzone container to open file dialog.", - }, - disabled: { - value: false, - type: PropTypes.Boolean, - description: "Renders component in disabled state.", + hidden: true, }, errorMessage: { - value: "", + value: undefined, type: PropTypes.String, description: "Error message to be displayed.", - stateful: true, + hidden: true, }, ...changeHandlers.reduce((acc, current) => { //@ts-ignore @@ -104,15 +141,24 @@ const FileUploaderConfig: TConfig = { description: "Lets you customize all aspects of the component.", custom: { names: [ - { ...buttonConfig, componentName: "ButtonComponent" }, - { ...buttonConfig, componentName: "CancelButtonComponent" }, - { ...buttonConfig, componentName: "RetryButtonComponent" }, - "ContentMessage", - "ErrorMessage", - "FileDragAndDrop", - "HiddenInput", - "Spinner", - "ProgressBar", + { ...iconConfig, componentName: "AlertIcon" }, + { ...iconConfig, componentName: "CircleCheckFilledIcon" }, + "FileRow", + "FileRowColumn", + "FileRowContent", + "FileRowFileName", + "FileRowText", + "FileRowUploadMessage", + "FileRowUploadText", + "FileRows", + "Hint", + "ImagePreviewThumbnail", + "ItemPreviewContainer", + "Label", + { ...iconConfig, componentName: "PaperclipFilledIcon" }, + "ParentRoot", + { ...iconConfig, componentName: "TrashCanFilledIcon" }, + "TrashCanFilledIconContainer", ], sharedProps: {}, }, diff --git a/documentation-site/examples/bottom-navigation/overflow.tsx b/documentation-site/examples/bottom-navigation/overflow.tsx index 3a43f459b6..747cd3a8a3 100644 --- a/documentation-site/examples/bottom-navigation/overflow.tsx +++ b/documentation-site/examples/bottom-navigation/overflow.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { styled } from "baseui/styles"; import { BottomNavigation, NavItem } from "baseui/bottom-navigation"; import { MessageCard } from "baseui/message-card"; -import { FileUploader } from "baseui/file-uploader"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; import { colors } from "baseui/tokens"; import Calendar from "baseui/icon/calendar"; import Alert from "baseui/icon/alert"; @@ -126,7 +126,7 @@ export default function Example() {

File Upload

- + diff --git a/documentation-site/examples/file-uploader/_overrides_component.tsx b/documentation-site/examples/file-uploader-basic/_overrides_component.tsx similarity index 77% rename from documentation-site/examples/file-uploader/_overrides_component.tsx rename to documentation-site/examples/file-uploader-basic/_overrides_component.tsx index 10d4e457bf..a92386ea13 100644 --- a/documentation-site/examples/file-uploader/_overrides_component.tsx +++ b/documentation-site/examples/file-uploader-basic/_overrides_component.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; -import {FileUploader} from 'baseui/file-uploader'; -import {FileUploaderOverrides} from 'baseui/file-uploader'; +import * as React from "react"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; +import { FileUploaderBasicOverrides } from "baseui/file-uploader-basic"; export default class Uploader extends React.Component< - {overrides: FileUploaderOverrides}, - {progressAmount: number} + { overrides: FileUploaderBasicOverrides }, + { progressAmount: number } > { - state = {progressAmount: 0}; + state = { progressAmount: 0 }; intervalId: number = 0; // startProgress method is only illustrative. Use the progress info returned @@ -26,13 +26,13 @@ export default class Uploader extends React.Component< // reset the component to its original state. use this to cancel/retry the upload. reset = () => { clearInterval(this.intervalId); - this.setState({progressAmount: 0}); + this.setState({ progressAmount: 0 }); }; render() { return ( - { // handle file upload... @@ -42,24 +42,24 @@ export default class Uploader extends React.Component< progressMessage={ this.state.progressAmount ? `Uploading... ${this.state.progressAmount}% of 100%` - : '' + : "" } overrides={this.props.overrides} />

- { // handle file upload... this.startProgress(); }} progressAmount={this.state.progressAmount} - errorMessage={'Something went wrong. Sorry!'} + errorMessage={"Something went wrong. Sorry!"} progressMessage={ this.state.progressAmount ? `Uploading... ${this.state.progressAmount}% of 100%` - : '' + : "" } overrides={this.props.overrides} /> diff --git a/documentation-site/examples/file-uploader-basic/basic.tsx b/documentation-site/examples/file-uploader-basic/basic.tsx new file mode 100644 index 0000000000..3d65c8e234 --- /dev/null +++ b/documentation-site/examples/file-uploader-basic/basic.tsx @@ -0,0 +1,74 @@ +import * as React from "react"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; + +// https://overreacted.io/making-setinterval-declarative-with-react-hooks/ +function useInterval(callback: any, delay: number | null) { + const savedCallback = React.useRef(() => {}); + + // Remember the latest callback. + React.useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + // Set up the interval. + React.useEffect((): any => { + function tick() { + savedCallback.current(); + } + if (delay !== null) { + let id = setInterval(tick, delay); + return () => clearInterval(id); + } + }, [delay]); +} + +// useFakeProgress is an elaborate way to show a fake file transfer for illustrative purposes. You +// don't need this is your application. Use metadata from your upload destination if it's available, +// or don't provide progress. +function useFakeProgress(): [number, () => void, () => void] { + const [fakeProgress, setFakeProgress] = React.useState(0); + const [isActive, setIsActive] = React.useState(false); + + function stopFakeProgress() { + setIsActive(false); + setFakeProgress(0); + } + + function startFakeProgress() { + setIsActive(true); + } + + useInterval( + () => { + if (fakeProgress >= 100) { + stopFakeProgress(); + } else { + setFakeProgress(fakeProgress + 10); + } + }, + isActive ? 500 : null, + ); + + return [fakeProgress, startFakeProgress, stopFakeProgress]; +} + +export default function Example() { + const [progressAmount, startFakeProgress, stopFakeProgress] = + useFakeProgress(); + + return ( + { + // handle file upload... + console.log(acceptedFiles, rejectedFiles); + startFakeProgress(); + }} + // progressAmount is a number from 0 - 100 which indicates the percent of file transfer completed + progressAmount={progressAmount} + progressMessage={ + progressAmount ? `Uploading... ${progressAmount}% of 100%` : "" + } + /> + ); +} diff --git a/documentation-site/examples/file-uploader-basic/disabled.tsx b/documentation-site/examples/file-uploader-basic/disabled.tsx new file mode 100644 index 0000000000..5b5a02c2cd --- /dev/null +++ b/documentation-site/examples/file-uploader-basic/disabled.tsx @@ -0,0 +1,6 @@ +import * as React from "react"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; + +export default function Example() { + return ; +} diff --git a/documentation-site/examples/file-uploader/error.tsx b/documentation-site/examples/file-uploader-basic/error.tsx similarity index 96% rename from documentation-site/examples/file-uploader/error.tsx rename to documentation-site/examples/file-uploader-basic/error.tsx index 34506f5991..c3347d85f2 100644 --- a/documentation-site/examples/file-uploader/error.tsx +++ b/documentation-site/examples/file-uploader-basic/error.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { FileUploader } from "baseui/file-uploader"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; // https://overreacted.io/making-setinterval-declarative-with-react-hooks/ function useInterval(callback: () => void, delay: number | null) { @@ -60,7 +60,7 @@ export default function Example() { useFakeProgress(); return ( - { // handle file upload... diff --git a/documentation-site/examples/file-uploader-basic/overrides.tsx b/documentation-site/examples/file-uploader-basic/overrides.tsx new file mode 100644 index 0000000000..c59792d887 --- /dev/null +++ b/documentation-site/examples/file-uploader-basic/overrides.tsx @@ -0,0 +1,102 @@ +import * as React from "react"; +import { FileUploaderBasic } from "baseui/file-uploader-basic"; + +// https://overreacted.io/making-setinterval-declarative-with-react-hooks/ +function useInterval(callback: any, delay: number | null) { + const savedCallback = React.useRef(() => {}); + + // Remember the latest callback. + React.useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + // Set up the interval. + React.useEffect((): any => { + function tick() { + savedCallback.current(); + } + if (delay !== null) { + let id = setInterval(tick, delay); + return () => clearInterval(id); + } + }, [delay]); +} + +// useFakeProgress is an elaborate way to show a fake file transfer for illustrative purposes. You +// don't need this is your application. Use metadata from your upload destination if it's available, +// or don't provide progress. +function useFakeProgress(): [number, () => void, () => void] { + const [fakeProgress, setFakeProgress] = React.useState(0); + const [isActive, setIsActive] = React.useState(false); + + function stopFakeProgress() { + setIsActive(false); + setFakeProgress(0); + } + + function startFakeProgress() { + setIsActive(true); + } + + useInterval( + () => { + if (fakeProgress >= 100) { + stopFakeProgress(); + } else { + setFakeProgress(fakeProgress + 10); + } + }, + isActive ? 500 : null, + ); + + return [fakeProgress, startFakeProgress, stopFakeProgress]; +} + +export default function Example() { + const [progressAmount, startFakeProgress, stopFakeProgress] = + useFakeProgress(); + + return ( + { + // handle file upload... + console.log(acceptedFiles, rejectedFiles); + startFakeProgress(); + }} + // progressAmount is a number from 0 - 100 which indicates the percent of file transfer completed + progressAmount={progressAmount} + progressMessage={ + progressAmount ? `Uploading... ${progressAmount}% of 100%` : "" + } + overrides={{ + FileDragAndDrop: { + style: (props) => ({ + borderLeftColor: props.$isDragActive + ? props.$theme.colors.positive + : props.$theme.colors.warning, + borderRightColor: props.$isDragActive + ? props.$theme.colors.positive + : props.$theme.colors.warning, + borderTopColor: props.$isDragActive + ? props.$theme.colors.positive + : props.$theme.colors.warning, + borderBottomColor: props.$isDragActive + ? props.$theme.colors.positive + : props.$theme.colors.warning, + }), + }, + ContentMessage: { + style: (props) => ({ + color: props.$theme.colors.warning, + }), + }, + ContentSeparator: { + style: (props) => ({ + color: props.$theme.colors.warning, + }), + }, + }} + /> + ); +} diff --git a/documentation-site/examples/file-uploader-beta/basic.tsx b/documentation-site/examples/file-uploader-beta/basic.tsx deleted file mode 100644 index 4cfebdf28b..0000000000 --- a/documentation-site/examples/file-uploader-beta/basic.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as React from "react"; -import { FileUploaderBeta, type FileRow } from "baseui/file-uploader-beta"; - -export default function Example() { - const [fileRows, setFileRows] = React.useState>([ - { - file: new File(["test file"], "file.txt"), - status: "processed", - errorMessage: null, - }, - ]); - - const processFileOnDrop = ( - file: File, - ): Promise<{ errorMessage: string | null; fileInfo?: any }> => { - return new Promise((resolve) => { - // Fake an upload process for 2 seconds - // For a real-world scenario, replace this with application upload logic - setTimeout(() => { - let fileInfo = { - file, - objectID: "1234", - uploadID: "1234", - uploadStatus: "success", - }; - resolve({ errorMessage: null, fileInfo }); - }, 2000); - }); - }; - - return ( - - ); -} diff --git a/documentation-site/examples/file-uploader-beta/overrides.tsx b/documentation-site/examples/file-uploader-beta/overrides.tsx deleted file mode 100644 index 7f1b6466c4..0000000000 --- a/documentation-site/examples/file-uploader-beta/overrides.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import * as React from "react"; -import { FileUploaderBeta, type FileRow } from "baseui/file-uploader-beta"; -import { useStyletron } from "baseui"; - -export default function Example() { - const [fileRows, setFileRows] = React.useState>([ - { - file: new File(["test file 1"], "file-1.txt"), - status: "processed", - errorMessage: null, - }, - { - file: new File(["test file 2"], "file-2.txt"), - status: "error", - errorMessage: "Failed to upload", - }, - ]); - const [, theme] = useStyletron(); - return ( - - ); -} diff --git a/documentation-site/examples/file-uploader/basic.tsx b/documentation-site/examples/file-uploader/basic.tsx index 07dc3dcce2..9e6b1e5a48 100644 --- a/documentation-site/examples/file-uploader/basic.tsx +++ b/documentation-site/examples/file-uploader/basic.tsx @@ -1,74 +1,39 @@ import * as React from "react"; -import { FileUploader } from "baseui/file-uploader"; - -// https://overreacted.io/making-setinterval-declarative-with-react-hooks/ -function useInterval(callback: any, delay: number | null) { - const savedCallback = React.useRef(() => {}); - - // Remember the latest callback. - React.useEffect(() => { - savedCallback.current = callback; - }, [callback]); - - // Set up the interval. - React.useEffect((): any => { - function tick() { - savedCallback.current(); - } - if (delay !== null) { - let id = setInterval(tick, delay); - return () => clearInterval(id); - } - }, [delay]); -} - -// useFakeProgress is an elaborate way to show a fake file transfer for illustrative purposes. You -// don't need this is your application. Use metadata from your upload destination if it's available, -// or don't provide progress. -function useFakeProgress(): [number, () => void, () => void] { - const [fakeProgress, setFakeProgress] = React.useState(0); - const [isActive, setIsActive] = React.useState(false); - - function stopFakeProgress() { - setIsActive(false); - setFakeProgress(0); - } - - function startFakeProgress() { - setIsActive(true); - } - - useInterval( - () => { - if (fakeProgress >= 100) { - stopFakeProgress(); - } else { - setFakeProgress(fakeProgress + 10); - } - }, - isActive ? 500 : null, - ); - - return [fakeProgress, startFakeProgress, stopFakeProgress]; -} +import { FileUploader, type FileRow } from "baseui/file-uploader"; export default function Example() { - const [progressAmount, startFakeProgress, stopFakeProgress] = - useFakeProgress(); + const [fileRows, setFileRows] = React.useState>([ + { + file: new File(["test file"], "file.txt"), + id: "0", + status: "processed", + errorMessage: null, + }, + ]); + + const processFileOnDrop = ( + file: File, + ): Promise<{ errorMessage: string | null; fileInfo?: any }> => { + return new Promise((resolve) => { + // Fake an upload process for 2 seconds + // For a real-world scenario, replace this with application upload logic + setTimeout(() => { + let fileInfo = { + file, + objectID: "1234", + uploadID: "1234", + uploadStatus: "success", + }; + resolve({ errorMessage: null, fileInfo }); + }, 2000); + }); + }; return ( { - // handle file upload... - console.log(acceptedFiles, rejectedFiles); - startFakeProgress(); - }} - // progressAmount is a number from 0 - 100 which indicates the percent of file transfer completed - progressAmount={progressAmount} - progressMessage={ - progressAmount ? `Uploading... ${progressAmount}% of 100%` : "" - } + fileRows={fileRows} + processFileOnDrop={processFileOnDrop} + setFileRows={setFileRows} /> ); } diff --git a/documentation-site/examples/file-uploader/disabled.tsx b/documentation-site/examples/file-uploader/disabled.tsx deleted file mode 100644 index d02150db4b..0000000000 --- a/documentation-site/examples/file-uploader/disabled.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import { FileUploader } from "baseui/file-uploader"; - -export default function Example() { - return ; -} diff --git a/documentation-site/examples/file-uploader-beta/item-preview.tsx b/documentation-site/examples/file-uploader/item-preview.tsx similarity index 82% rename from documentation-site/examples/file-uploader-beta/item-preview.tsx rename to documentation-site/examples/file-uploader/item-preview.tsx index 71013a6c38..f118821ab4 100644 --- a/documentation-site/examples/file-uploader-beta/item-preview.tsx +++ b/documentation-site/examples/file-uploader/item-preview.tsx @@ -1,16 +1,17 @@ import * as React from "react"; -import { FileUploaderBeta, type FileRow } from "baseui/file-uploader-beta"; +import { FileUploader, type FileRow } from "baseui/file-uploader"; export default function Example() { const [fileRows, setFileRows] = React.useState>([ { file: new File(["test file"], "file.txt"), + id: "0", status: "processed", errorMessage: null, }, ]); return ( - >([]); return ( - {}); - - // Remember the latest callback. - React.useEffect(() => { - savedCallback.current = callback; - }, [callback]); - - // Set up the interval. - React.useEffect((): any => { - function tick() { - savedCallback.current(); - } - if (delay !== null) { - let id = setInterval(tick, delay); - return () => clearInterval(id); - } - }, [delay]); -} - -// useFakeProgress is an elaborate way to show a fake file transfer for illustrative purposes. You -// don't need this is your application. Use metadata from your upload destination if it's available, -// or don't provide progress. -function useFakeProgress(): [number, () => void, () => void] { - const [fakeProgress, setFakeProgress] = React.useState(0); - const [isActive, setIsActive] = React.useState(false); - - function stopFakeProgress() { - setIsActive(false); - setFakeProgress(0); - } - - function startFakeProgress() { - setIsActive(true); - } - - useInterval( - () => { - if (fakeProgress >= 100) { - stopFakeProgress(); - } else { - setFakeProgress(fakeProgress + 10); - } - }, - isActive ? 500 : null, - ); - - return [fakeProgress, startFakeProgress, stopFakeProgress]; -} +import { FileUploader, type FileRow } from "baseui/file-uploader"; +import { useStyletron } from "baseui"; export default function Example() { - const [progressAmount, startFakeProgress, stopFakeProgress] = - useFakeProgress(); - + const [fileRows, setFileRows] = React.useState>([ + { + file: new File(["test file 1"], "file-1.txt"), + id: "0", + status: "processed", + errorMessage: null, + }, + { + file: new File(["test file 2"], "file-2.txt"), + id: "1", + status: "error", + errorMessage: "Failed to upload", + }, + ]); + const [, theme] = useStyletron(); return ( { - // handle file upload... - console.log(acceptedFiles, rejectedFiles); - startFakeProgress(); - }} - // progressAmount is a number from 0 - 100 which indicates the percent of file transfer completed - progressAmount={progressAmount} - progressMessage={ - progressAmount ? `Uploading... ${progressAmount}% of 100%` : "" - } + fileRows={fileRows} + setFileRows={setFileRows} overrides={{ - FileDragAndDrop: { - style: (props) => ({ - borderLeftColor: props.$isDragActive - ? props.$theme.colors.positive - : props.$theme.colors.warning, - borderRightColor: props.$isDragActive - ? props.$theme.colors.positive - : props.$theme.colors.warning, - borderTopColor: props.$isDragActive - ? props.$theme.colors.positive - : props.$theme.colors.warning, - borderBottomColor: props.$isDragActive - ? props.$theme.colors.positive - : props.$theme.colors.warning, - }), + ButtonComponent: { + props: { + overrides: { + BaseButton: { + style: { + outline: `${theme.colors.warning} solid`, + }, + }, + }, + }, }, ContentMessage: { - style: (props) => ({ - color: props.$theme.colors.warning, - }), + style: { + color: theme.colors.warning, + }, + }, + FileDragAndDrop: { + style: { + borderColor: theme.colors.warning, + borderStyle: "dashed", + borderWidth: theme.sizing.scale0, + }, }, - ContentSeparator: { - style: (props) => ({ - color: props.$theme.colors.warning, - }), + FileRows: { + style: { + marginLeft: theme.sizing.scale0, + marginRight: theme.sizing.scale0, + outline: `${theme.colors.warning} dashed`, + }, }, }} /> diff --git a/documentation-site/examples/file-uploader-beta/upload-restrictions.tsx b/documentation-site/examples/file-uploader/upload-restrictions.tsx similarity index 92% rename from documentation-site/examples/file-uploader-beta/upload-restrictions.tsx rename to documentation-site/examples/file-uploader/upload-restrictions.tsx index 493994ca04..90af79e406 100644 --- a/documentation-site/examples/file-uploader-beta/upload-restrictions.tsx +++ b/documentation-site/examples/file-uploader/upload-restrictions.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { FileUploaderBeta, type FileRow } from "baseui/file-uploader-beta"; +import { FileUploader, type FileRow } from "baseui/file-uploader"; export default function Example() { // Upload files to test restrictions. For demo purposes, @@ -7,21 +7,25 @@ export default function Example() { const [fileRows, setFileRows] = React.useState>([ { file: new File(["test file 1"], "unaccepted-file-type.jpeg"), + id: "0", status: "error", errorMessage: "file type of img/jpeg is not accepted", }, { file: new File(["test file 2"], "file-too-small.png"), + id: "1", status: "error", errorMessage: "file size must be greater than 20 KB", }, { file: new File(["test file 3"], "file-too-big.png"), + id: "2", status: "error", errorMessage: "file size must be less than 100 KB", }, { file: new File(["test file 4"], "file-count-too-many.png"), + id: "3", status: "error", errorMessage: "cannot process more than ${props.maxFiles} file(s)", }, @@ -46,7 +50,7 @@ export default function Example() { }; return ( - + +Creates a dropzone for file uploads. + +## Accessibility + +- "Browse files" has `aria-controls="fileupload"` set. + +## When to use + +- Enable file(s) upload through drag and drop or the system _Browse files_ dialog. + +## Security considerations + +By default, the file uploader basic does not concern itself with validating and discarding potentially malicious files, as Base Web never runs any of the uploaded files. **It's the responsibility of the consuming application to do so.** To help with that, this component supports the `accept` property, which can limit the acceptable file extensions. + +To learn more, read the corresponding [OWASP article on file uploads](https://www.owasp.org/index.php/Unrestricted_File_Upload). + +## Examples + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation-site/pages/components/file-uploader-beta.mdx b/documentation-site/pages/components/file-uploader-beta.mdx deleted file mode 100644 index 31f7d58f12..0000000000 --- a/documentation-site/pages/components/file-uploader-beta.mdx +++ /dev/null @@ -1,75 +0,0 @@ -import Example from "../../components/example"; -import Layout from "../../components/layout"; -import Exports from "../../components/exports"; - -import FileUploaderBetaBasic from "examples/file-uploader-beta/basic.tsx"; -import FileUploaderBetaItemPreview from "examples/file-uploader-beta/item-preview.tsx"; -import FileUploaderBetaLabelHint from "examples/file-uploader-beta/label-hint.tsx"; -import FileUploaderBetaUploadRestrictions from "examples/file-uploader-beta/upload-restrictions.tsx"; -import FileUploaderBetaOverrides from "examples/file-uploader-beta/overrides.tsx"; - -import * as FileUploaderBetaExports from "baseui/file-uploader-beta"; - -import Yard from "../../components/yard/index"; -import fileUploaderBetaYardConfig from "../../components/yard/config/file-uploader-beta"; - -export default Layout; - -# File Uploader Beta - - - -Creates a dropzone for file uploads with file row state binding, props to control errors, and props to control uploads. - -## Accessibility - -- "Browse files" has `aria-controls="fileupload"` set. - -## Inheritance - -- Inherits all props from the `FileUploader` component except for `onDrop`, `onDropAccepted`, and `onDropRejected`. These three props are replaced by the `processFileOnDrop` function prop. -- Inherits all style props from the `FileUploader` component. - -## How to use - -- Enable file(s) upload through drag and drop or the system _Browse files_ dialog. -- Leverage `accept`, `maxFiles`, `maxSize`, and `minSize` for built in error handling. -- Leverage `processFileOnDrop` for custom error handling and upload capabilities. Should take a `file: File` and input and return `Promise<{ errorMessage: string | null; fileInfo?: any }>` where `errorMessage` determines if an error is shown. -- Component will be `disabled` while files are uploading. This prevents invalid state while React re-renders via `useState` hook. - -## Security considerations - -By default, the file uploader does not concern itself with validating and discarding potentially malicious files, as Base Web never runs any of the uploaded files. **It's the responsibility of the consuming application to do so.** To help with that, this component supports the `accept` property, which can limit the acceptable file extensions. - -To learn more, read the corresponding [OWASP article on file uploads](https://www.owasp.org/index.php/Unrestricted_File_Upload). - -## Examples - - - - - - - - - - - - - - - - - - - - - - diff --git a/documentation-site/pages/components/file-uploader.mdx b/documentation-site/pages/components/file-uploader.mdx index 2492466c00..a7afb0736e 100644 --- a/documentation-site/pages/components/file-uploader.mdx +++ b/documentation-site/pages/components/file-uploader.mdx @@ -3,12 +3,11 @@ import Layout from "../../components/layout"; import Exports from "../../components/exports"; import FileUploaderBasic from "examples/file-uploader/basic.tsx"; -import FileUploaderError from "examples/file-uploader/error.tsx"; -import FileUploaderIndeterminate from "examples/file-uploader/indeterminate-progress.tsx"; -import FileUploaderDisabled from "examples/file-uploader/disabled.tsx"; +import FileUploaderItemPreview from "examples/file-uploader/item-preview.tsx"; +import FileUploaderLabelHint from "examples/file-uploader/label-hint.tsx"; +import FileUploaderUploadRestrictions from "examples/file-uploader/upload-restrictions.tsx"; import FileUploaderOverrides from "examples/file-uploader/overrides.tsx"; -import OverridesExample from "examples/file-uploader/_overrides_component.tsx"; import * as FileUploaderExports from "baseui/file-uploader"; import Yard from "../../components/yard/index"; @@ -18,17 +17,25 @@ export default Layout; # File Uploader - + -Creates a dropzone for file uploads. +Creates a dropzone for file uploads with file row state binding, props to control errors, and props to control uploads. ## Accessibility - "Browse files" has `aria-controls="fileupload"` set. -## When to use +## Inheritance + +- Inherits all props from the `FileUploaderBasic` component except for `onDrop`, `onDropAccepted`, and `onDropRejected`. These three props are replaced by the `processFileOnDrop` function prop. +- Inherits all style props from the `FileUploaderBasic` component. + +## How to use - Enable file(s) upload through drag and drop or the system _Browse files_ dialog. +- Leverage `accept`, `maxFiles`, `maxSize`, and `minSize` for built in error handling. +- Leverage `processFileOnDrop` for custom error handling and upload capabilities. Should take a `file: File` and input and return `Promise<{ errorMessage: string | null; fileInfo?: any }>` where `errorMessage` determines if an error is shown. +- Component will be `disabled` while files are uploading. This prevents invalid state while React re-renders via `useState` hook. ## Security considerations @@ -38,32 +45,26 @@ To learn more, read the corresponding [OWASP article on file uploads](https://ww ## Examples - + - - + + - - + + - + - + diff --git a/documentation-site/routes.jsx b/documentation-site/routes.jsx index a17965090f..7308b93230 100644 --- a/documentation-site/routes.jsx +++ b/documentation-site/routes.jsx @@ -137,8 +137,8 @@ const routes = [ itemId: "/components/file-uploader", }, { - title: "File Uploader Beta", - itemId: "/components/file-uploader-beta", + title: "File Uploader Basic", + itemId: "/components/file-uploader-basic", }, { title: "Menu", diff --git a/package.json b/package.json index e894a79a21..f63cec7dad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "baseui", - "version": "14.0.0", + "version": "15.0.0", "description": "A React Component library implementing the Base design language", "keywords": [ "react", diff --git a/src/banner/banner.tsx b/src/banner/banner.tsx index c49da75df0..d3034532a7 100644 --- a/src/banner/banner.tsx +++ b/src/banner/banner.tsx @@ -162,11 +162,16 @@ function Trailing({ action, backgroundColor, color, overrides, nested }) { StyledTrailingButtonContainer ); + const trailingButtonOverrides = overrides?.TrailingButton; + const trailingButtonBackgroundColor = trailingButtonOverrides?.style?.backgroundColor + ? trailingButtonOverrides.style.backgroundColor + : backgroundColor; + if (action.label) { return (