diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8aee13b..879aa92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 4.0.0 (2022-01-017)
+
+### โจ Features
+
+ * Improve code performance
+ * Rewrite any existing based components to hooks
+
+Credits
+
+* [@Bunlong](https://github.com/Bunlong)
+
## 3.18.2 (2022-01-04)
### โจ Bugs
diff --git a/README.md b/README.md
index 95aef9b..27f903f 100644
--- a/README.md
+++ b/README.md
@@ -43,11 +43,9 @@ To learn how to use react-papaparse:
* [Documentation](https://react-papaparse.github.io/docs)
-FAQ:
+
## ๐ Useful Features
@@ -66,108 +64,69 @@ FAQ:

```javascript
-import React, { Component } from 'react'
-
-import { CSVReader } from 'react-papaparse'
-
-const buttonRef = React.createRef()
-
-export default class CSVReader extends Component {
- handleOpenDialog = (e) => {
- // Note that the ref is set async, so it might be null at some point
- if (buttonRef.current) {
- buttonRef.current.open(e)
- }
- }
-
- handleOnFileLoad = (data) => {
- console.log('---------------------------')
- console.log(data)
- console.log('---------------------------')
- }
-
- handleOnError = (err, file, inputElem, reason) => {
- console.log(err)
- }
-
- handleOnRemoveFile = (data) => {
- console.log('---------------------------')
- console.log(data)
- console.log('---------------------------')
- }
-
- handleRemoveFile = (e) => {
- // Note that the ref is set async, so it might be null at some point
- if (buttonRef.current) {
- buttonRef.current.removeFile(e)
- }
- }
-
- render() {
- return (
-
- {({ file }) => (
-
- {`import { readString } from 'react-papaparse'
+ {`import React from 'react';
-const config = {
- worker: true,
- complete: (results) => {
- console.log(results)
- }
-}
+import { usePapaParse } from 'react-papaparse';
+
+export default function ReadString() {
+ const { readString } = usePapaParse();
+
+ const handleReadString = () => {
+ const csvString = 'Column 1,Column 2,Column 3,Column 4
+1-1,1-2,1-3,1-4
+2-1,2-2,2-3,2-4
+3-1,3-2,3-3,3-4
+4,5,6,7';
-readString(csvString, config)
+ readString(csvString, {
+ worker: true,
+ complete: (results) => {
+ console.log('---------------------------');
+ console.log(results);
+ console.log('---------------------------');
+ },
+ });
+ };
+
+ return ;
+}
/*
results = {
diff --git a/docs/src/components/screens/indexes/Delimiter.js b/docs/src/components/screens/indexes/Delimiter.js
index b0bdf94..87c0f34 100644
--- a/docs/src/components/screens/indexes/Delimiter.js
+++ b/docs/src/components/screens/indexes/Delimiter.js
@@ -13,14 +13,16 @@ const Delimiter = () => {
- {`import { readString } from 'react-papaparse'
-
-readString(csvString, {
+ {`const config = {
worker: true,
complete: (results) => {
- console.log(results.meta.delimiter)
- }
-})
+ console.log('---------------------------');
+ console.log(results.meta.delimiter);
+ console.log('---------------------------');
+ },
+};
+
+readString(csvString, config);
`}
diff --git a/docs/src/components/screens/indexes/LocalFile.js b/docs/src/components/screens/indexes/LocalFile.js
index 155e098..030b5ab 100644
--- a/docs/src/components/screens/indexes/LocalFile.js
+++ b/docs/src/components/screens/indexes/LocalFile.js
@@ -41,108 +41,69 @@ const LocalFile = () => {
- {`import React, { Component } from 'react'
+ {`import React, { CSSProperties } from 'react';
-import { CSVReader } from 'react-papaparse'
+import { useCSVReader } from 'react-papaparse';
-const buttonRef = React.createRef()
-
-export default class CSVReader extends Component {
- handleOpenDialog = (e) => {
- // Note that the ref is set async, so it might be null at some point
- if (buttonRef.current) {
- buttonRef.current.open(e)
- }
- }
-
- handleOnFileLoad = (data) => {
- console.log('---------------------------')
- console.log(data)
- console.log('---------------------------')
- }
-
- handleOnError = (err, file, inputElem, reason) => {
- console.log(err)
- }
-
- handleOnRemoveFile = (data) => {
- console.log('---------------------------')
- console.log(data)
- console.log('---------------------------')
- }
+const styles = {
+ csvReader: {
+ display: 'flex',
+ flexDirection: 'row',
+ marginBottom: 10,
+ } as CSSProperties,
+ browseFile: {
+ width: '20%',
+ } as CSSProperties,
+ acceptedFile: {
+ border: '1px solid #ccc',
+ height: 45,
+ lineHeight: 2.5,
+ paddingLeft: 10,
+ width: '80%',
+ } as CSSProperties,
+ remove: {
+ borderRadius: 0,
+ padding: '0 20px',
+ } as CSSProperties,
+ progressBarBackgroundColor: {
+ backgroundColor: 'red',
+ } as CSSProperties,
+};
- handleRemoveFile = (e) => {
- // Note that the ref is set async, so it might be null at some point
- if (buttonRef.current) {
- buttonRef.current.removeFile(e)
- }
- }
+export default function CSVReader() {
+ const { CSVReader } = useCSVReader();
- render() {
- return (
-
- {({ file }) => (
-
-
diff --git a/docs/static/css/home.css b/docs/static/css/home.css
index 580086c..85c31e8 100644
--- a/docs/static/css/home.css
+++ b/docs/static/css/home.css
@@ -1,5 +1,6 @@
#top {
- padding: 6% 0 8%;
+ /*padding: 6% 0 8%;*/
+ padding: 8% 0 15%;
color: #1D80AB;
background: #FFF;
position: relative;
@@ -176,7 +177,8 @@ footer {
@media (max-width: 1150px) {
#title-main h1 {
- font-size: 5.41vw;
+ /*font-size: 5.41vw;*/
+ font-size: 7.41vw;
letter-spacing: -2px;
}
@@ -216,9 +218,9 @@ footer {
display: none;
}
- #top {
+ /*#top {
padding-top: 0;
- }
+ }*/
#title-main,
#title-main h1,
diff --git a/docs/static/js/prism.js b/docs/static/js/prism.js
deleted file mode 100644
index f5a096e..0000000
--- a/docs/static/js/prism.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/* PrismJS 1.19.0
-https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
-var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,C={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof _?new _(e.type,C.util.encode(e.content),e.alias):Array.isArray(e)?e.map(C.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(k instanceof _)){if(h&&y!=n.length-1){if(c.lastIndex=v,!(O=c.exec(e)))break;for(var b=O.index+(f&&O[1]?O[1].length:0),w=O.index+O[0].length,A=y,P=v,x=n.length;A"+r.content+""+r.tag+">"},!u.document)return u.addEventListener&&(C.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,t=n.code,a=n.immediateClose;u.postMessage(C.highlight(t,C.languages[r],r)),a&&u.close()},!1)),C;var e=C.util.currentScript();if(e&&(C.filename=e.src,e.hasAttribute("data-manual")&&(C.manual=!0)),!C.manual){function r(){C.manual||C.highlightAll()}var t=document.readyState;"loading"===t||"interactive"===t&&e&&e.defer?document.addEventListener("DOMContentLoaded",r):window.requestAnimationFrame?window.requestAnimationFrame(r):window.setTimeout(r,16)}return C}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
-Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:(?!)*\]\s*)?>/i,greedy:!0},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var n={"included-cdata":{pattern://i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp("(<__[\\s\\S]*?>)(?:\\s*|[\\s\\S])*?(?=<\\/__>)".replace(/__/g,a),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",t)}}),Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
-!function(s){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/@[\w-]+/}},url:{pattern:RegExp("url\\((?:"+t.source+"|[^\n\r()]*)\\)","i"),inside:{function:/^url/i,punctuation:/^\(|\)$/}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+t.source+")*?(?=\\s*\\{)"),string:{pattern:t,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var e=s.languages.markup;e&&(e.tag.addInlined("style","css"),s.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:e.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:s.languages.css}},alias:"language-css"}},e.tag))}(Prism);
-Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
-Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&|\|\||[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?[.?]?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*[\s\S]*?\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript;
diff --git a/examples/CSVDownloader.tsx b/examples/CSVDownloader.tsx
new file mode 100644
index 0000000..ea0dee0
--- /dev/null
+++ b/examples/CSVDownloader.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+
+import { useCSVDownloader } from 'react-papaparse';
+
+export default function CSVDownloader() {
+ const { CSVDownloader, Type } = useCSVDownloader();
+
+ return (
+
+ Download
+
+ );
+}
diff --git a/examples/CSVReaderBasicUpload.tsx b/examples/CSVReaderBasicUpload.tsx
new file mode 100644
index 0000000..d791f7b
--- /dev/null
+++ b/examples/CSVReaderBasicUpload.tsx
@@ -0,0 +1,64 @@
+import React, { CSSProperties } from 'react';
+
+import { useCSVReader } from 'react-papaparse';
+
+const styles = {
+ csvReader: {
+ display: 'flex',
+ flexDirection: 'row',
+ marginBottom: 10,
+ } as CSSProperties,
+ browseFile: {
+ width: '20%',
+ } as CSSProperties,
+ acceptedFile: {
+ border: '1px solid #ccc',
+ height: 45,
+ lineHeight: 2.5,
+ paddingLeft: 10,
+ width: '80%',
+ } as CSSProperties,
+ remove: {
+ borderRadius: 0,
+ padding: '0 20px',
+ } as CSSProperties,
+ progressBarBackgroundColor: {
+ backgroundColor: 'red',
+ } as CSSProperties,
+};
+
+export default function CSVReader() {
+ const { CSVReader } = useCSVReader();
+
+ return (
+ {
+ console.log('---------------------------');
+ console.log(results);
+ console.log('---------------------------');
+ }}
+ >
+ {({
+ getRootProps,
+ acceptedFile,
+ ProgressBar,
+ getRemoveFileProps,
+ }: any) => (
+ <>
+
+
+ Browse file
+
+
+ {acceptedFile && acceptedFile.name}
+
+
+ Remove
+
+
+
+ >
+ )}
+
+ );
+}
diff --git a/examples/CSVReaderClickAndDragUpload.tsx b/examples/CSVReaderClickAndDragUpload.tsx
new file mode 100644
index 0000000..bc527ed
--- /dev/null
+++ b/examples/CSVReaderClickAndDragUpload.tsx
@@ -0,0 +1,158 @@
+import React, { useState, CSSProperties } from 'react';
+
+import {
+ useCSVReader,
+ lightenDarkenColor,
+ formatFileSize,
+} from 'react-papaparse';
+
+const GREY = '#CCC';
+const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
+const DEFAULT_REMOVE_HOVER_COLOR = '#A01919';
+const REMOVE_HOVER_COLOR_LIGHT = lightenDarkenColor(
+ DEFAULT_REMOVE_HOVER_COLOR,
+ 40
+);
+const GREY_DIM = '#686868';
+
+const styles = {
+ zone: {
+ alignItems: 'center',
+ border: `2px dashed ${GREY}`,
+ borderRadius: 20,
+ display: 'flex',
+ flexDirection: 'column',
+ height: '100%',
+ justifyContent: 'center',
+ padding: 20,
+ } as CSSProperties,
+ file: {
+ background: 'linear-gradient(to bottom, #EEE, #DDD)',
+ borderRadius: 20,
+ display: 'flex',
+ height: 120,
+ width: 120,
+ position: 'relative',
+ zIndex: 10,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ } as CSSProperties,
+ info: {
+ alignItems: 'center',
+ display: 'flex',
+ flexDirection: 'column',
+ paddingLeft: 10,
+ paddingRight: 10,
+ } as CSSProperties,
+ size: {
+ backgroundColor: GREY_LIGHT,
+ borderRadius: 3,
+ marginBottom: '0.5em',
+ justifyContent: 'center',
+ display: 'flex',
+ } as CSSProperties,
+ name: {
+ backgroundColor: GREY_LIGHT,
+ borderRadius: 3,
+ fontSize: 12,
+ marginBottom: '0.5em',
+ } as CSSProperties,
+ progressBar: {
+ bottom: 14,
+ position: 'absolute',
+ width: '100%',
+ paddingLeft: 10,
+ paddingRight: 10,
+ } as CSSProperties,
+ zoneHover: {
+ borderColor: GREY_DIM,
+ } as CSSProperties,
+ default: {
+ borderColor: GREY,
+ } as CSSProperties,
+ remove: {
+ height: 23,
+ position: 'absolute',
+ right: 6,
+ top: 6,
+ width: 23,
+ } as CSSProperties,
+};
+
+export default function CSVReader() {
+ const { CSVReader } = useCSVReader();
+ const [zoneHover, setZoneHover] = useState(false);
+ const [removeHoverColor, setRemoveHoverColor] = useState(
+ DEFAULT_REMOVE_HOVER_COLOR
+ );
+
+ return (
+ {
+ console.log('---------------------------');
+ console.log(results);
+ console.log('---------------------------');
+ setZoneHover(false);
+ }}
+ onDragOver={(event: DragEvent) => {
+ event.preventDefault();
+ setZoneHover(true);
+ }}
+ onDragLeave={(event: DragEvent) => {
+ event.preventDefault();
+ setZoneHover(false);
+ }}
+ >
+ {({
+ getRootProps,
+ acceptedFile,
+ ProgressBar,
+ getRemoveFileProps,
+ Remove,
+ }: any) => (
+ <>
+
+ {acceptedFile ? (
+ <>
+
+
+
+ {formatFileSize(acceptedFile.size)}
+
+ {acceptedFile.name}
+
+
+
{
+ event.preventDefault();
+ setRemoveHoverColor(REMOVE_HOVER_COLOR_LIGHT);
+ }}
+ onMouseOut={(event: Event) => {
+ event.preventDefault();
+ setRemoveHoverColor(DEFAULT_REMOVE_HOVER_COLOR);
+ }}
+ >
+
+
+
+ >
+ ) : (
+ 'Drop CSV file here or click to upload'
+ )}
+
+ >
+ )}
+
+ );
+}
diff --git a/examples/CSVReaderClickNoDragUpload.tsx b/examples/CSVReaderClickNoDragUpload.tsx
new file mode 100644
index 0000000..851823c
--- /dev/null
+++ b/examples/CSVReaderClickNoDragUpload.tsx
@@ -0,0 +1,159 @@
+import React, { useState, CSSProperties } from 'react';
+
+import {
+ useCSVReader,
+ lightenDarkenColor,
+ formatFileSize,
+} from 'react-papaparse';
+
+const GREY = '#CCC';
+const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
+const DEFAULT_REMOVE_HOVER_COLOR = '#A01919';
+const REMOVE_HOVER_COLOR_LIGHT = lightenDarkenColor(
+ DEFAULT_REMOVE_HOVER_COLOR,
+ 40
+);
+const GREY_DIM = '#686868';
+
+const styles = {
+ zone: {
+ alignItems: 'center',
+ border: `2px dashed ${GREY}`,
+ borderRadius: 20,
+ display: 'flex',
+ flexDirection: 'column',
+ height: '100%',
+ justifyContent: 'center',
+ padding: 20,
+ } as CSSProperties,
+ file: {
+ background: 'linear-gradient(to bottom, #EEE, #DDD)',
+ borderRadius: 20,
+ display: 'flex',
+ height: 120,
+ width: 120,
+ position: 'relative',
+ zIndex: 10,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ } as CSSProperties,
+ info: {
+ alignItems: 'center',
+ display: 'flex',
+ flexDirection: 'column',
+ paddingLeft: 10,
+ paddingRight: 10,
+ } as CSSProperties,
+ size: {
+ backgroundColor: GREY_LIGHT,
+ borderRadius: 3,
+ marginBottom: '0.5em',
+ justifyContent: 'center',
+ display: 'flex',
+ } as CSSProperties,
+ name: {
+ backgroundColor: GREY_LIGHT,
+ borderRadius: 3,
+ fontSize: 12,
+ marginBottom: '0.5em',
+ } as CSSProperties,
+ progressBar: {
+ bottom: 14,
+ position: 'absolute',
+ width: '100%',
+ paddingLeft: 10,
+ paddingRight: 10,
+ } as CSSProperties,
+ zoneHover: {
+ borderColor: GREY_DIM,
+ } as CSSProperties,
+ default: {
+ borderColor: GREY,
+ } as CSSProperties,
+ remove: {
+ height: 23,
+ position: 'absolute',
+ right: 6,
+ top: 6,
+ width: 23,
+ } as CSSProperties,
+};
+
+export default function CSVReader() {
+ const { CSVReader } = useCSVReader();
+ const [zoneHover, setZoneHover] = useState(false);
+ const [removeHoverColor, setRemoveHoverColor] = useState(
+ DEFAULT_REMOVE_HOVER_COLOR
+ );
+
+ return (
+ {
+ console.log('---------------------------');
+ console.log(results);
+ console.log('---------------------------');
+ setZoneHover(false);
+ }}
+ onDragOver={(event: DragEvent) => {
+ event.preventDefault();
+ setZoneHover(true);
+ }}
+ onDragLeave={(event: DragEvent) => {
+ event.preventDefault();
+ setZoneHover(false);
+ }}
+ noDrag
+ >
+ {({
+ getRootProps,
+ acceptedFile,
+ ProgressBar,
+ getRemoveFileProps,
+ Remove,
+ }: any) => (
+ <>
+
+ {acceptedFile ? (
+ <>
+
+
+
+ {formatFileSize(acceptedFile.size)}
+
+ {acceptedFile.name}
+
+
+
{
+ event.preventDefault();
+ setRemoveHoverColor(REMOVE_HOVER_COLOR_LIGHT);
+ }}
+ onMouseOut={(event: Event) => {
+ event.preventDefault();
+ setRemoveHoverColor(DEFAULT_REMOVE_HOVER_COLOR);
+ }}
+ >
+
+
+
+ >
+ ) : (
+ 'Click to upload'
+ )}
+
+ >
+ )}
+
+ );
+}
diff --git a/examples/CSVReaderDragNoClickUpload.tsx b/examples/CSVReaderDragNoClickUpload.tsx
new file mode 100644
index 0000000..dee2d53
--- /dev/null
+++ b/examples/CSVReaderDragNoClickUpload.tsx
@@ -0,0 +1,159 @@
+import React, { useState, CSSProperties } from 'react';
+
+import {
+ useCSVReader,
+ lightenDarkenColor,
+ formatFileSize,
+} from 'react-papaparse';
+
+const GREY = '#CCC';
+const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
+const DEFAULT_REMOVE_HOVER_COLOR = '#A01919';
+const REMOVE_HOVER_COLOR_LIGHT = lightenDarkenColor(
+ DEFAULT_REMOVE_HOVER_COLOR,
+ 40
+);
+const GREY_DIM = '#686868';
+
+const styles = {
+ zone: {
+ alignItems: 'center',
+ border: `2px dashed ${GREY}`,
+ borderRadius: 20,
+ display: 'flex',
+ flexDirection: 'column',
+ height: '100%',
+ justifyContent: 'center',
+ padding: 20,
+ } as CSSProperties,
+ file: {
+ background: 'linear-gradient(to bottom, #EEE, #DDD)',
+ borderRadius: 20,
+ display: 'flex',
+ height: 120,
+ width: 120,
+ position: 'relative',
+ zIndex: 10,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ } as CSSProperties,
+ info: {
+ alignItems: 'center',
+ display: 'flex',
+ flexDirection: 'column',
+ paddingLeft: 10,
+ paddingRight: 10,
+ } as CSSProperties,
+ size: {
+ backgroundColor: GREY_LIGHT,
+ borderRadius: 3,
+ marginBottom: '0.5em',
+ justifyContent: 'center',
+ display: 'flex',
+ } as CSSProperties,
+ name: {
+ backgroundColor: GREY_LIGHT,
+ borderRadius: 3,
+ fontSize: 12,
+ marginBottom: '0.5em',
+ } as CSSProperties,
+ progressBar: {
+ bottom: 14,
+ position: 'absolute',
+ width: '100%',
+ paddingLeft: 10,
+ paddingRight: 10,
+ } as CSSProperties,
+ zoneHover: {
+ borderColor: GREY_DIM,
+ } as CSSProperties,
+ default: {
+ borderColor: GREY,
+ } as CSSProperties,
+ remove: {
+ height: 23,
+ position: 'absolute',
+ right: 6,
+ top: 6,
+ width: 23,
+ } as CSSProperties,
+};
+
+export default function CSVReader() {
+ const { CSVReader } = useCSVReader();
+ const [zoneHover, setZoneHover] = useState(false);
+ const [removeHoverColor, setRemoveHoverColor] = useState(
+ DEFAULT_REMOVE_HOVER_COLOR
+ );
+
+ return (
+ {
+ console.log('---------------------------');
+ console.log(results);
+ console.log('---------------------------');
+ setZoneHover(false);
+ }}
+ onDragOver={(event: DragEvent) => {
+ event.preventDefault();
+ setZoneHover(true);
+ }}
+ onDragLeave={(event: DragEvent) => {
+ event.preventDefault();
+ setZoneHover(false);
+ }}
+ noClick
+ >
+ {({
+ getRootProps,
+ acceptedFile,
+ ProgressBar,
+ getRemoveFileProps,
+ Remove,
+ }: any) => (
+ <>
+
+ {acceptedFile ? (
+ <>
+
+
+
+ {formatFileSize(acceptedFile.size)}
+
+ {acceptedFile.name}
+
+
+
{
+ event.preventDefault();
+ setRemoveHoverColor(REMOVE_HOVER_COLOR_LIGHT);
+ }}
+ onMouseOut={(event: Event) => {
+ event.preventDefault();
+ setRemoveHoverColor(DEFAULT_REMOVE_HOVER_COLOR);
+ }}
+ >
+
+
+
+ >
+ ) : (
+ 'Drop CSV file here to upload'
+ )}
+
+ >
+ )}
+
+ );
+}
diff --git a/examples/jsonToCSV.tsx b/examples/jsonToCSV.tsx
new file mode 100644
index 0000000..4142af9
--- /dev/null
+++ b/examples/jsonToCSV.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+
+import { usePapaParse } from 'react-papaparse';
+
+export default function JsonToCSV() {
+ const { jsonToCSV } = usePapaParse();
+
+ const handleJsonToCSV = () => {
+ const jsonData = `[
+ {
+ "Column 1": "1-1",
+ "Column 2": "1-2",
+ "Column 3": "1-3",
+ "Column 4": "1-4"
+ },
+ {
+ "Column 1": "2-1",
+ "Column 2": "2-2",
+ "Column 3": "2-3",
+ "Column 4": "2-4"
+ },
+ {
+ "Column 1": "3-1",
+ "Column 2": "3-2",
+ "Column 3": "3-3",
+ "Column 4": "3-4"
+ },
+ {
+ "Column 1": 4,
+ "Column 2": 5,
+ "Column 3": 6,
+ "Column 4": 7
+ }
+ ]`;
+ const results = jsonToCSV(jsonData);
+ console.log('---------------------------');
+ console.log('Results:', results);
+ console.log('---------------------------');
+ };
+
+ return handleJsonToCSV()}>jsonToCSV;
+}
diff --git a/examples/readRemoteFile.tsx b/examples/readRemoteFile.tsx
new file mode 100644
index 0000000..68ac5d7
--- /dev/null
+++ b/examples/readRemoteFile.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+
+import { usePapaParse } from 'react-papaparse';
+
+export default function ReadRemoteFile() {
+ const { readRemoteFile } = usePapaParse();
+
+ const handleReadRemoteFile = () => {
+ readRemoteFile('https://react-papaparse.js.org/static/csv/normal.csv', {
+ complete: (results) => {
+ console.log('---------------------------');
+ console.log('Results:', results);
+ console.log('---------------------------');
+ },
+ });
+ };
+
+ return handleReadRemoteFile()}>readRemoteFile;
+}
diff --git a/demo/ReadString.js b/examples/readString.tsx
similarity index 57%
rename from demo/ReadString.js
rename to examples/readString.tsx
index 5583e56..d631062 100644
--- a/demo/ReadString.js
+++ b/examples/readString.tsx
@@ -1,8 +1,11 @@
-import React, { Component } from 'react';
-import { readString } from 'react-papaparse';
+import React from 'react';
-export default class ReadString extends Component {
- handleClick = () => {
+import { usePapaParse } from 'react-papaparse';
+
+export default function ReadString() {
+ const { readString } = usePapaParse();
+
+ const handleReadString = () => {
const csvString = `Column 1,Column 2,Column 3,Column 4
1-1,1-2,1-3,1-4
2-1,2-2,2-3,2-4
@@ -19,7 +22,5 @@ export default class ReadString extends Component {
});
};
- render() {
- return readString;
- }
+ return handleReadString()}>readString;
}
diff --git a/package.json b/package.json
index 4d95d82..e570a9e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-papaparse",
- "version": "3.18.2",
+ "version": "4.0.0",
"description": "The fastest in-browser CSV (or delimited text) parser for React. It is full of useful features such as CSVReader, CSVDownloader, readString, jsonToCSV, readRemoteFile, ... etc.",
"author": "Bunlong ",
"license": "MIT",
@@ -67,7 +67,7 @@
"scripts": {
"test": "jest --runInBand",
"build": "rollup -c",
- "prettier": "prettier --write './src/*.ts' './src/*.tsx' './demo/*js' --config ./.prettierrc",
+ "prettier": "prettier --write './src/*.ts' './src/*.tsx' --config ./.prettierrc",
"lint:check": "eslint ./src --ext .tsx,.ts --report-unused-disable-directives",
"bundlesize": "npm run build && bundlesize",
"dev": "rollup -c -w",
diff --git a/src/CSVDownloader.tsx b/src/CSVDownloader.tsx
deleted file mode 100644
index 4e42051..0000000
--- a/src/CSVDownloader.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import React from 'react';
-import PapaParse, { UnparseConfig } from 'papaparse';
-
-export const LINK_TYPE = 'link';
-export const BUTTON_TYPE = 'button';
-
-export interface Props {
- children: React.ReactNode;
- data: any;
- filename: string;
- type?: 'link' | 'button';
- style?: any;
- className?: string;
- bom?: boolean;
- config?: UnparseConfig;
-}
-
-export default class CSVDownloader extends React.Component {
- static defaultProps: Partial = {
- type: LINK_TYPE,
- };
-
- // https://github.com/mholt/PapaParse/issues/175
- download = (
- data: any,
- filename: string,
- bom: boolean,
- config: UnparseConfig,
- ): void => {
- const bomCode = bom ? '\ufeff' : '';
- let csvContent = null;
- let csvURL = null;
-
- if (typeof data === 'function') {
- data = data();
- }
-
- if (typeof data === 'object') {
- csvContent = PapaParse.unparse(data, config);
- } else {
- csvContent = data;
- }
-
- const csvData = new Blob([`${bomCode}${csvContent}`], {
- type: 'text/csv;charset=utf-8;',
- });
-
- const navObj: any = window.navigator;
- if (navObj.msSaveBlob) {
- csvURL = navObj.msSaveBlob(csvData, `${filename}.csv`);
- } else {
- csvURL = window.URL.createObjectURL(csvData);
- }
-
- const link = document.createElement('a');
- link.href = csvURL as string;
- link.setAttribute('download', `${filename}.csv`);
- link.click();
- link.remove();
- };
-
- render(): React.ReactNode {
- const {
- children,
- data,
- filename,
- type,
- className,
- style,
- bom = false,
- config = {},
- } = this.props;
-
- if (type === LINK_TYPE) {
- return (
- this.download(data, filename, bom, config)}
- className={className}
- style={style}
- >
- {children}
-
- );
- }
-
- return (
- this.download(data, filename, bom, config)}
- className={className}
- style={style}
- >
- {children}
-
- );
- }
-}
diff --git a/src/CSVReader.tsx b/src/CSVReader.tsx
deleted file mode 100644
index 350dcf5..0000000
--- a/src/CSVReader.tsx
+++ /dev/null
@@ -1,588 +0,0 @@
-import React, { CSSProperties } from 'react';
-import PapaParse, { ParseResult } from 'papaparse';
-import { CustomConfig } from './model';
-import getSize, { lightenDarkenColor } from './utils';
-import RemoveIcon from './RemoveIcon';
-import ProgressBar from './ProgressBar';
-
-const GREY = '#CCC';
-const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
-const REMOVE_ICON_DEFAULT_COLOR = '#A01919';
-const GREY_DIM = '#686868';
-// 'text/csv' for MacOS
-// '.csv' for Linux
-// 'application/vnd.ms-excel' for Window 10
-const DEFAULT_ACCEPT = 'text/csv, .csv, application/vnd.ms-excel';
-
-const styles = {
- dropArea: {
- alignItems: 'center',
- borderStyle: 'dashed',
- borderWidth: 2,
- borderRadius: 20,
- borderColor: GREY,
- display: 'flex',
- flexDirection: 'column',
- height: '100%',
- justifyContent: 'center',
- padding: 20,
- } as CSSProperties,
- dropAreaDefaultBorderColor: {
- borderColor: GREY,
- },
- inputFile: {
- display: 'none',
- } as CSSProperties,
- highlight: {
- borderColor: GREY_DIM,
- },
- unhighlight: {
- borderColor: GREY,
- } as CSSProperties,
- dropFile: {
- background: 'linear-gradient(to bottom, #EEE, #DDD)',
- borderRadius: 20,
- display: 'block',
- height: 120,
- width: 100,
- paddingLeft: 10,
- paddingRight: 10,
- position: 'relative',
- zIndex: 10,
- } as CSSProperties,
- column: {
- alignItems: 'center',
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- } as CSSProperties,
- fileSizeInfo: {
- backgroundColor: GREY_LIGHT,
- borderRadius: 3,
- lineHeight: 1,
- marginBottom: '0.5em',
- padding: '0 0.4em',
- } as CSSProperties,
- fileNameInfo: {
- backgroundColor: GREY_LIGHT,
- borderRadius: 3,
- fontSize: 14,
- lineHeight: 1,
- padding: '0 0.4em',
- } as CSSProperties,
- defaultCursor: {
- cursor: 'default',
- } as CSSProperties,
- pointerCursor: {
- cursor: 'pointer',
- } as CSSProperties,
- dropFileRemoveButton: {
- height: 23,
- position: 'absolute',
- right: 6,
- top: 6,
- width: 23,
- } as CSSProperties,
-};
-
-interface Props {
- children: any;
- onDrop?: (data: Array>, file?: any) => void;
- onFileLoad?: (data: Array>, file?: any) => void;
- onError?: (err: any, file: any, inputElem: any, reason: any) => void;
- config?: CustomConfig;
- style?: any;
- noClick?: boolean;
- noDrag?: boolean;
- progressBarColor?: string;
- addRemoveButton?: boolean;
- onRemoveFile?: (data: null) => void;
- noProgressBar?: boolean;
- removeButtonColor?: string;
- isReset?: boolean;
- accept?: string;
-}
-
-interface State {
- dropAreaCustom: any;
- progressBar: number;
- displayProgressBarStatus: string;
- file: any;
- timeout: any;
- files: any;
- removeIconColor: string;
- isCanceled: boolean;
-}
-
-export default class CSVReader extends React.Component<
- Props,
- State
-> {
- static defaultProps: Partial> = {
- isReset: false,
- };
-
- // TODO
- // inputFileRef: React.RefObject = React.createRef()
- inputFileRef: any = React.createRef();
- dropAreaRef: any = React.createRef();
- fileSizeInfoRef: any = React.createRef();
- fileNameInfoRef: any = React.createRef();
-
- // TODO: Delete this.props.removeButtonColor
- REMOVE_ICON_COLOR =
- this.props.removeButtonColor ||
- this.props.style?.dropArea?.dropFile?.removeButton?.color ||
- this.props.style?.dropFile?.removeButton?.color ||
- this.props.style?.removeButton?.color ||
- REMOVE_ICON_DEFAULT_COLOR;
- REMOVE_ICON_COLOR_LIGHT = lightenDarkenColor(this.REMOVE_ICON_COLOR, 40);
-
- state = {
- dropAreaCustom: {},
- progressBar: 0,
- displayProgressBarStatus: 'none',
- file: null,
- timeout: null,
- files: null,
- removeIconColor: this.REMOVE_ICON_COLOR,
- isCanceled: false,
- } as State;
-
- componentDidUpdate = (prevProps: any) => {
- if (this.props.isReset !== prevProps.isReset) {
- this.removeFile();
- }
- };
-
- componentDidMount = () => {
- const currentDropAreaRef = this.dropAreaRef.current;
- if (currentDropAreaRef) {
- const fourDragsEvent = ['dragenter', 'dragover', 'dragleave', 'drop'];
- fourDragsEvent.forEach((item) => {
- currentDropAreaRef.addEventListener(item, this.preventDefaults, false);
- });
-
- if (!this.props.noDrag) {
- const highlightDragsEvent = ['dragenter', 'dragover'];
- highlightDragsEvent.forEach((item) => {
- currentDropAreaRef.addEventListener(item, this.highlight, false);
- });
- currentDropAreaRef.addEventListener(
- 'dragleave',
- this.unhighlight,
- false,
- );
- currentDropAreaRef.addEventListener('drop', this.unhighlight, false);
- currentDropAreaRef.addEventListener(
- 'drop',
- this.visibleProgressBar,
- false,
- );
- currentDropAreaRef.addEventListener('drop', this.handleDrop, false);
- }
- }
- };
-
- componentWillUnmount = () => {
- const currentDropAreaRef = this.dropAreaRef.current;
-
- const fourDragsEvent = ['dragenter', 'dragover', 'dragleave', 'drop'];
- fourDragsEvent.forEach((item) => {
- currentDropAreaRef.removeEventListener(item, this.preventDefaults, false);
- });
-
- if (!this.props.noDrag) {
- const highlightDragsEvent = ['dragenter', 'dragover'];
- highlightDragsEvent.forEach((item) => {
- currentDropAreaRef.removeEventListener(item, this.highlight, false);
- });
- currentDropAreaRef.removeEventListener(
- 'dragleave',
- this.unhighlight,
- false,
- );
- currentDropAreaRef.removeEventListener('drop', this.unhighlight, false);
- currentDropAreaRef.removeEventListener(
- 'drop',
- this.visibleProgressBar,
- false,
- );
- currentDropAreaRef.removeEventListener('drop', this.handleDrop, false);
- }
- };
-
- preventDefaults = (e: any) => {
- e.preventDefault();
- e.stopPropagation();
- };
-
- highlight = () => {
- const { style } = this.props;
- this.setState({
- dropAreaCustom: Object.assign(
- {},
- style?.dropAreaActive
- ? style?.dropAreaActive.borderColor
- ? style?.dropAreaActive
- : Object.assign({}, style?.dropAreaActive, styles.highlight)
- : style?.dropArea?.dropAreaActive
- ? style?.dropArea?.dropAreaActive.borderColor
- ? style?.dropArea?.dropAreaActive
- : Object.assign(
- {},
- style?.dropArea?.dropAreaActive,
- styles.highlight,
- )
- : styles.highlight,
- ),
- });
- this.setState({ progressBar: 0 });
- };
-
- unhighlight = () => {
- this.setState({
- dropAreaCustom: Object.assign(
- {},
- this.props.style?.dropArea?.borderColor
- ? {}
- : styles.dropAreaDefaultBorderColor,
- ),
- });
- };
-
- visibleProgressBar = () => {
- if (!this.props.noProgressBar) {
- this.setState({ displayProgressBarStatus: 'block' });
- }
- };
-
- handleDrop = (e: any) => {
- let files = null;
- let isCanceled = false;
-
- if (e.files === undefined) {
- const dt = e.dataTransfer;
- files = dt.files;
- } else {
- files = e.files;
- }
-
- if (files.length === 0) {
- files = this.state.files;
- isCanceled = true;
- }
-
- this.setState({ files, isCanceled }, () => {
- this.handleFiles();
- });
- };
-
- handleFiles = () => {
- this.setState({ progressBar: 0 });
- let files = null;
- files = [...this.state.files];
- files.forEach(this.uploadFile);
- };
-
- uploadFile = (file: any) => {
- this.displayFileInfo(file);
- this.setState({ file });
-
- const { onDrop, onFileLoad, onError, config = {} } = this.props;
- const reader = new window.FileReader();
- let options = {};
-
- const size = file.size;
- const data: any = [];
- let percent = 0;
-
- if (onDrop || onFileLoad) {
- const self = this;
- options = Object.assign(
- {
- complete:
- config?.complete || config?.step
- ? config.complete
- : () => {
- if (!onDrop && onFileLoad) {
- onFileLoad(data, file);
- } else if (onDrop && !onFileLoad) {
- onDrop(data, file);
- }
- },
- step: config?.step
- ? config.step
- : (row: any) => {
- data.push(row);
- if (config && config.preview) {
- percent = Math.round((data.length / config.preview) * 100);
- self.setState({ progressBar: percent });
- if (data.length === config.preview) {
- if (!onDrop && onFileLoad) {
- onFileLoad(data, file);
- } else if (onDrop && !onFileLoad) {
- onDrop(data, file);
- }
- }
- } else {
- const progress = row.meta.cursor;
- const newPercent = Math.round((progress / size) * 100);
- if (newPercent === percent) {
- return;
- }
- percent = newPercent;
- }
- self.setState({ progressBar: percent });
- },
- },
- options,
- );
- }
-
- if (onError) {
- options = Object.assign({ error: onError }, options);
- }
-
- if (config) {
- options = Object.assign({}, config, options);
- }
-
- reader.onload = (e: any) => {
- PapaParse.parse(e.target.result, options);
- };
-
- if (!this.props.noProgressBar) {
- reader.onloadend = () => {
- clearTimeout(this.state.timeout);
- this.setState({
- timeout: setTimeout(() => {
- this.disableProgressBar();
- }, 2000),
- });
- };
- }
-
- reader.readAsText(file, config.encoding || 'utf-8');
- };
-
- displayFileInfo = (file: any) => {
- if (!this.childrenIsFunction()) {
- this.fileSizeInfoRef.current.innerHTML = getSize(file.size);
- this.fileNameInfoRef.current.innerHTML = file.name;
- }
- };
-
- disableProgressBar = () => {
- if (!this.props.noProgressBar) {
- this.setState({ displayProgressBarStatus: 'none' });
- }
- };
-
- childrenIsFunction = () => {
- return typeof this.props.children === 'function';
- };
-
- fileChange = (e: any) => {
- const { target } = e;
- if (!this.props.noProgressBar) {
- this.setState({ displayProgressBarStatus: 'block' }, () => {
- this.handleDrop(target);
- });
- } else {
- this.handleDrop(target);
- }
- };
-
- open = (e: any) => {
- const { displayProgressBarStatus } = this.state;
- if (e && displayProgressBarStatus === 'none') {
- this.preventDefaults(e);
- this.inputFileRef.current.value = null;
- this.inputFileRef.current.click();
- }
- };
-
- renderChildren = () => {
- const { children } = this.props;
- const { file, progressBar } = this.state;
- return this.childrenIsFunction()
- ? children({ file, progressBar })
- : children;
- };
-
- handleRemoveFile = (e: any) => {
- if (e) {
- e.stopPropagation();
- this.removeFile();
- }
- };
-
- removeFile = () => {
- this.setState({ files: null, file: null });
-
- const { onRemoveFile } = this.props;
- if (onRemoveFile) {
- onRemoveFile(null);
- }
-
- this.inputFileRef.current.value = null;
- };
-
- changeRemoveIconColor = (color: string) => {
- if (color) {
- this.setState({ removeIconColor: color });
- }
- };
-
- renderDropFileRemoveButton = () => {
- const { addRemoveButton } = this.props;
- const { removeIconColor, displayProgressBarStatus } = this.state;
-
- if (addRemoveButton && displayProgressBarStatus === 'none') {
- return (
- this.handleRemoveFile(e)}
- onMouseOver={() =>
- this.changeRemoveIconColor(this.REMOVE_ICON_COLOR_LIGHT)
- }
- onMouseOut={() => this.changeRemoveIconColor(this.REMOVE_ICON_COLOR)}
- >
-
-
- );
- }
-
- if (addRemoveButton) {
- return (
-
-
-
- );
- }
-
- return null;
- };
-
- render() {
- const {
- style,
- noClick,
- children,
- noProgressBar,
- progressBarColor,
- accept,
- } = this.props;
- const {
- dropAreaCustom,
- files,
- isCanceled,
- progressBar,
- displayProgressBarStatus,
- } = this.state;
-
- return (
- <>
- this.fileChange(e)}
- />
- {!this.childrenIsFunction() ? (
- {
- if (!noClick) {
- this.open(e);
- }
- }}
- >
- {files && files.length > 0 ? (
-
- {this.renderDropFileRemoveButton()}
-
-
-
-
- {files && files.length > 0 && !isCanceled && !noProgressBar && (
-
- )}
-
- ) : (
- children
- )}
-
- ) : (
-
- {this.renderChildren()}
- {files && files.length > 0 && !isCanceled && !noProgressBar && (
-
- )}
-
- )}
- >
- );
- }
-}
diff --git a/src/ProgressBar.tsx b/src/ProgressBar.tsx
index d52fdb7..1d13f05 100644
--- a/src/ProgressBar.tsx
+++ b/src/ProgressBar.tsx
@@ -1,4 +1,4 @@
-import React, { CSSProperties } from 'react';
+import React, { CSSProperties, useState, useEffect } from 'react';
const DEFAULT_PROGRESS_BAR_COLOR = '#659cef';
@@ -7,14 +7,14 @@ const styles = {
borderRadius: 3,
boxShadow: 'inset 0 1px 3px rgba(0, 0, 0, .2)',
bottom: 14,
- position: 'absolute',
- width: '80%',
+ width: '100%',
+ // position: 'absolute',
} as CSSProperties,
- buttonProgressBar: {
+ button: {
position: 'inherit',
width: '100%',
} as CSSProperties,
- progressBarFill: {
+ fill: {
backgroundColor: DEFAULT_PROGRESS_BAR_COLOR,
borderRadius: 3,
height: 10,
@@ -23,36 +23,28 @@ const styles = {
};
interface Props {
- style: any;
- progressBar: number;
- displayProgressBarStatus: string;
- isButtonProgressBar?: boolean;
+ style?: any;
+ className?: string;
+ percentage: number;
+ display: string;
+ isButton?: boolean;
}
-export default class ProgressBar extends React.Component {
- render() {
- const {
- style,
- progressBar,
- displayProgressBarStatus,
- isButtonProgressBar,
- } = this.props;
+export default function ProgressBar(props: Props) {
+ const { style, className, display } = props;
+ const [percentage, setPercentage] = useState(0);
+
+ useEffect(() => {
+ setPercentage(props.percentage);
+ }, [props.percentage]);
- return (
-
-
-
- );
- }
+ return (
+
+ );
}
diff --git a/src/RemoveIcon.tsx b/src/Remove.tsx
similarity index 74%
rename from src/RemoveIcon.tsx
rename to src/Remove.tsx
index 6a1184a..93e369e 100644
--- a/src/RemoveIcon.tsx
+++ b/src/Remove.tsx
@@ -1,15 +1,21 @@
import React from 'react';
-export default function RemoveIcon(props: { color: string }) {
+export interface Props {
+ color?: string;
+ width?: number;
+ height?: number;
+}
+
+export default function Remove({ color, width = 23, height = 23 }: Props) {
return (