File
General
Use the default fetch (opens in a new tab) method
Show Code
import React from "react";
import File from 'funda-ui/File';
export default () => {
function handleChange(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, submitEl, value);
}
function handleComplete(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, value);
}
function handleProgress(files: any[], input: HTMLInputElement, submitEl: HTMLElement) {
console.log(files);
}
return (
<>
<File
fetchUrl="http://api"
fetchMethod="POST"
fetchParams={{
Authorization: `Bearer xxxx-xxxx-xxxx-xxxx`,
}}
label="Select file"
labelClassName="btn btn-outline-secondary"
labelHoverClassName="btn btn-primary"
submitLabel="Upload"
submitClassName="btn btn-primary mt-2"
onChange={handleChange}
onComplete={handleComplete}
onProgress={handleProgress}
/>
</>
);
}No spacing
Show Code
import React from "react";
import File from 'funda-ui/File';
export default () => {
return (
<>
<File
...
wrapperClassName="position-relative"
...
/>
<File
...
wrapperClassName=""
...
/>
</>
);
}Upload controls and buttons are on the same line
Use the inline attribute.
Show Code
import React from "react";
import File from 'funda-ui/File';
export default () => {
return (
<>
<File
...
inline
...
/>
</>
);
}Proactively specify the type of upload
Use the accept attribute.
Show Code
import React from "react";
import File from 'funda-ui/File';
export default () => {
return (
<>
<File
...
accept="image/*"
...
/>
</>
);
}Use a custom API interface:
Show Code
import React from "react";
import File from 'funda-ui/File';
class UploadService {
// `upto()` must be a Promise Object
async upto(param1 = '', limit = 0) {
alert(`searchStr: ${param1} limit: ${limit}`);
// processing stream type via php/java/go/...
// ...
return {
code: 0,
message: 'OK',
data: 'upload successfully'
};
}
}
export default () => {
function handleChange(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, submitEl, value);
}
function handleComplete(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, value);
}
function handleProgress(files: any[], input: HTMLInputElement, submitEl: HTMLElement) {
console.log(files);
}
return (
<>
<File
fetchFuncAsync={new UploadService}
fetchFuncMethod="upto"
fetchFuncMethodParams={['',0]}
label="Select file"
labelClassName="btn btn-outline-secondary"
labelHoverClassName="btn btn-primary"
submitLabel="Upload"
submitClassName="btn btn-primary mt-2"
onChange={handleChange}
onComplete={handleComplete}
onProgress={handleProgress}
inline
/>
</>
);
}Access streams of data with this component
[]
Show Code
import React, { useState } from "react";
import File from 'funda-ui/File';
export default () => {
const [filesData, setFilesData] = useState<any[]>([]);
const getExt = (filename: string) => {
const ext = /^.+\.([^.]+)$/.exec(filename);
return ext == null ? "" : ext[1];
};
/**
* base64 to ArrayBuffer
* @param {String} data
* @returns {ArrayBuffer}
*/
/*
@returns:
ArrayBuffer(522240)
byteLength: 522240
detached: false
maxByteLength: 522240
resizable: false
[[Prototype]]: ArrayBuffer
[[Int8Array]]: Int8Array(522240)
[[Uint8Array]]: Uint8Array(522240)
[[Int16Array]]: Int16Array(261120)
[[Int32Array]]: Int32Array(130560)
[[ArrayBufferByteLength]]: 522240
[[ArrayBufferData]]: 673
*/
function base64ToArrayBuffer(data) {
let res = data;
if (data.indexOf('base64,') >= 0) {
res = data.split('base64,')[1];
}
//
const binaryString = atob(res);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
/**
* ArrayBuffer to Uint8Array
* @param {ArrayBuffer} data
* @returns {Uint8Array}
*/
/*
@returns:
Uint8Array(522240) [208, 207, 17, 224, 161, 177, 26, 225, 0, 0, ......]
*/
function arrayBufferToUint8Array(data) {
const bytes = new Uint8Array(data);
return bytes;
}
function handleChange(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
setFilesData([]);
console.log(input, submitEl, value);
}
function handleComplete(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, value);
}
function handleProgress(files: any[], input: HTMLInputElement, submitEl: HTMLElement) {
if (files.length === 0) {
alert('Please select a file')
return;
} else {
// setFilesData
[].slice.call(files).forEach((file: any) => {
const size = file.size;
const mimeType = file.type;
const name = file.name;
const ext = getExt(name);
// get file content
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const b64string = (event.currentTarget as any).result;
const arrayBufferData = base64ToArrayBuffer(b64string);
const uint8ArrayData = arrayBufferToUint8Array(arrayBufferData);
console.log(b64string);
console.log(arrayBufferData);
console.log(uint8ArrayData);
// save to database
// ...
});
reader.readAsDataURL(file);
setFilesData((prevState: any) => [...prevState, {
size,
mimeType,
name,
ext
}]);
});
}
}
return (
<>
<p>{JSON.stringify(filesData)}</p>
<File
label="Select file"
labelClassName="btn btn-outline-secondary"
labelHoverClassName="btn btn-primary"
submitLabel="Upload"
submitClassName="btn btn-primary mt-2"
onChange={handleChange}
onComplete={handleComplete}
onProgress={handleProgress}
multiple
/>
</>
);
}Customize the business upload component
Show Code [Uploader.tsx]
import React, { forwardRef, useRef } from 'react';
import File from 'funda-ui/File';
type UploaderProps = {
label?: React.ReactNode | string;
name?: string;
id?: string;
accept?: string;
wrapperClassName?: string;
waitingClassName?: string;
support?: string;
fetchUrl?: string;
fetchMethod?: string;
fetchParams?: any;
labelClassName?: string;
labelHoverClassName?: string;
inline?: boolean;
autoSubmit?: boolean;
multiple?: boolean;
submitLabel?: React.ReactNode | string;
submitClassName?: string;
progressLabel?: React.ReactNode | string;
progressClassName?: string;
onSuccess?: (data: any, input: HTMLInputElement, submitEl: HTMLElement) => void;
onChange?: () => void;
onProgress?: () => void;
onEmpty?: () => void;
onIncorrectFormat?: () => void;
};
const Uploader = forwardRef((props: UploaderProps, externalRef: any) => {
const {
label,
name,
id,
wrapperClassName,
waitingClassName,
accept,
support,
fetchUrl,
fetchMethod,
fetchParams,
labelClassName,
labelHoverClassName,
inline,
autoSubmit,
multiple,
submitLabel,
submitClassName,
progressLabel,
progressClassName,
onSuccess,
onProgress,
onChange,
onEmpty,
onIncorrectFormat,
...attributes
} = props;
const WAITING_CLASS = waitingClassName || '';
const hasFormatErr = useRef<boolean>(false);
const SUPPORT_EXT = support || 'jpg|jpeg|png|gif|webp';
const conRef = useRef<any>(null);
const handleChange = (input: HTMLInputElement, submitEl: HTMLElement, value: any) => {
onChange?.();
submitEl.classList.remove(WAITING_CLASS);
hasFormatErr.current = false;
};
const handleComplete = (input: HTMLInputElement, submitEl: HTMLElement, value: any) => {
if (hasFormatErr.current) {
submitEl.classList.remove(WAITING_CLASS);
return;
}
if (typeof value !== 'undefined') {
submitEl.classList.remove(WAITING_CLASS);
onSuccess?.(value, input, submitEl);
}
};
const handleProgress = (files: any[], input: HTMLInputElement, submitEl: HTMLElement) => {
if (files.length === 0) {
onEmpty?.();
return false;
}
hasFormatErr.current = false;
submitEl.classList.add(WAITING_CLASS);
onProgress?.();
// check format
[].slice.call(files).forEach((file: any) => {
if (typeof support === 'undefined' || support !== '*') {
const re = new RegExp(`\.(${SUPPORT_EXT})$`, "i");
if (! re.test(file.name)) {
onIncorrectFormat?.();
hasFormatErr.current = true;
submitEl.classList.remove(WAITING_CLASS);
}
}
});
// You can intercept requests or responses before they are handled by then or catch.
// This function could set a return value (Boolean). If "false", the request will be intercepted.
return !hasFormatErr.current;
};
return (
<>
<div className={wrapperClassName || ''}>
<File
{...attributes}
contentRef={conRef}
ref={externalRef}
label={label}
name={name}
id={id}
accept={accept}
fetchUrl={fetchUrl}
fetchMethod={fetchMethod}
fetchParams={fetchParams}
labelClassName={labelClassName}
labelHoverClassName={labelHoverClassName}
inline={inline || false}
multiple={multiple || false}
submitLabel={submitLabel}
submitClassName={submitClassName}
progressLabel={progressLabel}
progressClassName={progressClassName}
onChange={handleChange}
onComplete={handleComplete}
onProgress={handleProgress}
autoSubmit={autoSubmit}
/>
</div>
</>
)
});
Uploader.displayName = 'Uploader';
export default Uploader;Show Code [index.tsx]
import React, { useState } from "react";
import Uploader from './Uploader';
export default () => {
const [upInfoProgImgs, setUpInfoProgImgs] = useState<any>(null);
return (
<>
<Uploader
waitingClassName="app-button-state--waiting"
// fetchUrl={"https://api"}
// fetchMethod="POST"
// fetchParams={{ 'Authorization': 'Bearer xxxx-xxxx-xxxx-xxxx' }}
inline
support="jpg|jpeg|png|gif|webp" // "*" means all
labelClassName="btn btn-outline-secondary d-flex align-items-center"
labelHoverClassName="btn btn-primary d-flex align-items-center"
submitLabel="Upload"
progressLabel="Uploading..."
submitClassName="btn btn-primary ms-2"
label={<><svg width="15px" height="15px" viewBox="0 -2 32 32">
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g transform="translate(-258.000000, -467.000000)" fill="#000000">
<path d="M286,471 L283,471 L282,469 C281.411,467.837 281.104,467 280,467 L268,467 C266.896,467 266.53,467.954 266,469 L265,471 L262,471 C259.791,471 258,472.791 258,475 L258,491 C258,493.209 259.791,495 262,495 L286,495 C288.209,495 290,493.209 290,491 L290,475 C290,472.791 288.209,471 286,471 Z M274,491 C269.582,491 266,487.418 266,483 C266,478.582 269.582,475 274,475 C278.418,475 282,478.582 282,483 C282,487.418 278.418,491 274,491 Z M274,477 C270.687,477 268,479.687 268,483 C268,486.313 270.687,489 274,489 C277.313,489 280,486.313 280,483 C280,479.687 277.313,477 274,477 L274,477 Z">
</path>
</g>
</g>
</svg> Select</>}
onSuccess={(data: any) => {
io('BRIDGE_ALERT', { process: 0, info: 'Upload Successfully' });
const res = {
imgData: data.b64string,
imgName: data.fileData.name
};
//
setUpInfoProgImgs(res);
}}
onChange={() => {
setUpInfoProgImgs(null);
}}
onEmpty={() => {
io('BRIDGE_ALERT', { process: 0, info: 'No files are selected' });
}}
onIncorrectFormat={() => {
io('BRIDGE_ALERT', { process: 0, info: 'Incorrect file' })
}}
/>
{upInfoProgImgs !== null ? <div><img src={upInfoProgImgs.imgData} height={70} /></div> : null}
</>
);
}Use the exposed method to upload automatically or manually
Lets you callback the handle exposed as attribute contentRef. Set the property autoSubmit to true and it will be uploaded automatically.
Show Code
import React, { useRef } from 'react';
import File from 'funda-ui/File';
export default () => {
const conRef = useRef<any>(null);
function handleChange(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, submitEl, value);
}
function handleComplete(input: HTMLInputElement, submitEl: HTMLElement, value: any) {
console.log(input, value);
}
function handleProgress(files: any[], input: HTMLInputElement, submitEl: HTMLElement) {
console.log(files);
}
return (
<>
<button
type="button"
className="btn bg-primary-subtle text-black mb-2"
onClick={(e: React.MouseEvent) => {
if (conRef.current) conRef.current.upload();
}}
>Upload Manually</button>
<File
contentRef={conRef}
label="Select file"
labelClassName="btn btn-outline-secondary"
labelHoverClassName="btn btn-primary"
submitLabel="Upload"
submitClassName="btn btn-primary mt-2"
onChange={handleChange}
onComplete={handleComplete}
onProgress={handleProgress}
// autoSubmit // Enable automatic upload
/>
</>
)
}API
File
import File from 'funda-ui/File';| Property | Type | Default | Description | Required |
|---|---|---|---|---|
ref | React.ForwardedRef | - | It is the return element of this component. | - |
contentRef | React.RefObject | - | It exposes the following methods:
| - |
wrapperClassName | string | mb-3 position-relative | The class name of the control wrapper. | - |
controlClassName | string | form-control | The class name of the control. | - |
controlExClassName | string | - | The extended class name of controlClassName. | - |
labelClassName | string | btn btn-outline-secondary | The class name of the label. | - |
labelHoverClassName | string | btn btn-primary | The class name of the select button on hover. | - |
submitLabel | string | ReactNode | - | Specifies a label for submit button | - |
submitClassName | string | btn btn-primary mt-2 | The class name of the submit button. | - |
progressLabel | string | ReactNode | same as submitLabel | Specifies a label for submit button in progress | - |
progressClassName | string | same as submitClassName | The class name of the submit button in progress. | - |
inline | boolean | false | If true the group are on the same horizontal row. | - |
autoSubmit | boolean | false | Enable automatic upload, which will hide the upload button. | - |
fetchUrl | string | - | If the URL exists, it is passed using the default fetch method (Fetch API (opens in a new tab)). If it does not exist, the file content is read by ReadableStream (opens in a new tab) | - |
fetchMethod | string | POST | The request's method (GET, POST, etc.) Valid when the | - |
fetchParams | JSON Object | - | Set of query parameters in the request Valid when the | - |
multiple | boolean | false | A file upload field that accepts multiple values | - |
accept | string | - | The accept attribute takes as its value a comma-separated list of one or more file types, or unique file type specifiers, describing which file types to allow. such as video/*, image/*, image/png, image/jpeg, video/*, image/*,.pdf, `` | - |
value | string | - | Set a default value for this control | - |
requiredLabel | string | ReactNode | <span className="text-danger">*</span> | It is used to specify a label for an element required. | - |
label | string | ReactNode | <svg width="25px" height="25px" viewBox="0 0 1024 1024"><path d="M512 256l144.8 144.8-36.2 36.2-83-83v311.6h-51.2V354l-83 83-36.2-36.2L512 256zM307.2 716.8V768h409.6v-51.2H307.2z" fill="#000000" fillRule="evenodd"/></svg> | It is used to specify a label for an element of a form. | - |
name | string | - | Name is not deprecated when used with form fields. | - |
disabled | boolean | false | Whether it is disabled | - |
required | boolean | false | When present, it specifies that a field must be filled out before submitting the form. | - |
data You could use key (opens in a new tab) instead of it | any | - | Incoming data, you can set the third parameter of onComplete. Changes in the | - |
fetchFuncAsync | Constructor | - | A method as a string from the constructor. | - |
fetchFuncMethod | string | - | When the property is true, every time the select changes, a data request will be triggered. The methord must be a Promise Object. | - |
fetchFuncMethodParams | array | - | The parameter passed by the method, it is an array. Note: the first element is a query string, the second element is the number of queried data (usually a number), and then you can increase the third, or fourth, and more parameters. Such as ['',0], ['',99,'string 1','string 2'] There should be at least one parameter which is the query string. | - |
onChange | function | - | Call a function when the value of an HTML element is changed. It returns three callback values.
| - |
onProgress | function | - | Call a function when upload is in progress. It returns three callback values.
You can intercept requests or responses before they are handled by then or catch. This function could set a return value (Boolean). If "false", the request will be intercepted. | - |
onComplete | function | - | Call a function when the modal is submitted. It returns four callback values.
| - |
It accepts all props which this control support. Such as style, data-*, tabIndex, id, and so on.