Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
{
"stage": 0,
"loose": "all",
"presets": [
[
"latest",
{
"es2015": {
"modules": false
}
}
],
"react",
"stage-0"
]
}
19 changes: 14 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-dropzone-s3-uploader",
"version": "1.1.0",
"version": "1.2.1",
"description": "Drag and drop s3 file uploader via react-dropzone + react-s3-uploader",
"main": "lib/index.js",
"author": {
Expand All @@ -20,16 +20,25 @@
},
"dependencies": {
"prop-types": "^15.5.8",
"react": "^16.0.0",
"react-dropzone": "^4.0.0",
"react-s3-uploader": "4.5.0"
},
"devDependencies": {
"babel": "^5.6.14",
"babel-core": "^5.6.15",
"babel-eslint": "^4.1.3",
"babel-cli": "6.18.0",
"babel-core": "6.21.0",
"babel-eslint": "7.1.1",
"babel-loader": "6.2.10",
"babel-plugin-react-transform": "2.0.2",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-es2015-modules-commonjs": "6.18.0",
"babel-preset-latest": "6.16.0",
"babel-preset-react": "6.16.0",
"babel-preset-stage-0": "6.16.0",
"eslint": "^1.5.1",
"eslint-config-founderlab": "^0.1.0",
"eslint-plugin-react": "^3.4.2",
"expect": "^1.12.2"
"expect": "^1.12.2",
"webpack": "^3.8.1"
}
}
26 changes: 15 additions & 11 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@ For more detailed docs see the source packages

`s3Url` and `upload` are the only props that require configuration. All others have sensible defaults that may be overridden.

Prop | Type | Description
----------------- | ----------------- | -------------------------------------------
s3Url | string.isRequired | The url of your s3 bucket (`https://my-bucket.s3.amazonaws.com`)

Prop | Type | Description
----------------- | ----------------- | -------------------------------------------
s3Url | string | The url of your s3 bucket (`https://my-bucket.s3.amazonaws.com`)
upload | object.isRequired | Upload options passed to react-s3-uploader. See [react-s3-uploader](https://github.com/odysseyscience/react-s3-uploader) for available options. Don't set `onProgress`, `onError` or `onFinish` here - use the ones below
filename | string | Used as the default value if present. Filename of an image already hosted on s3 (i.e. one that was uploaded previously)
fileName | string | Used as the default value if present. Filename of an image already hosted on s3 (i.e. one that was uploaded previously)
notDropzoneProps | array | A list of props to *not* pass to `react-dropzone`
isImage | func | A function that takes a filename and returns true if it's an image
imageComponent | func | Component used to render an uploaded image
fileComponent | func | Component used to render an uploaded file
progressComponent | func | Component used to render upload progress
errorComponent | func | Component used to render an error
children | node \|\| func | If present the above components will be ignored in favour of the children
containerStyle | object | Parent container style
placeChildrenOutsideDropArea | node | Place react children outside the DropArea
childrenDropzone | node | Component used inside the DropArea when placeChildrenOutsideDropArea is true
passChildrenProps | bool | If true we pass the current state to children of this component. Default is true. Set to false to avoid React warnings about unused props.
onDrop | func | Called when a file is dropped onto the uploader
onError | func | Called when an upload error occurs
Expand All @@ -43,13 +46,14 @@ import DropzoneS3Uploader from 'react-dropzone-s3-uploader'
export default class S3Uploader extends React.Component {

handleFinishedUpload = info => {
console.log('File uploaded with filename', info.filename)
console.log('File uploaded with filename', info.fileName)
console.log('Access it on s3 at', info.fileUrl)
}

render() {
const uploadOptions = {
server: 'http://localhost:4000',
signUrl: '/s3/sign',
signingUrlQueryParams: {uploadType: 'avatar'},
}
const s3Url = 'https://my-bucket.s3.amazonaws.com'
Expand All @@ -73,10 +77,10 @@ Specify your own component to display uploaded files. Passed a list of `uploaded

// elsewhere
class UploadDisplay extends React.Component {

renderFileUpload = (uploadedFile, i) => {
const {
filename, // s3 filename
fileName, // s3 filename
fileUrl, // full s3 url of the file
file, // file descriptor from the upload
} = uploadedFile
Expand All @@ -92,7 +96,7 @@ class UploadDisplay extends React.Component {
render() {
const {uploadedFiles, s3Url} = this.props
return (
<div>
<div>
{uploadedFiles.map(this.renderFileUpload)}
</div>
)
Expand All @@ -106,8 +110,8 @@ class S3Uploader extends React.Component {

render() {
return (
<DropzoneS3Uploader
onFinish={this.handleFinishedUpload}
<DropzoneS3Uploader
onFinish={this.handleFinishedUpload}
upload={uploadOptions}
>
<UploadDisplay />
Expand Down
62 changes: 41 additions & 21 deletions src/DropzoneS3Uploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import Dropzone from 'react-dropzone'
export default class DropzoneS3Uploader extends React.Component {

static propTypes = {
filename: PropTypes.string,
s3Url: PropTypes.string.isRequired,
fileName: PropTypes.string,
s3Url: PropTypes.string,
notDropzoneProps: PropTypes.array.isRequired,
isImage: PropTypes.func.isRequired,
isImage: PropTypes.func,
passChildrenProps: PropTypes.bool,

// if true, all the child nodes will be placed outside the dropArea
placeChildrenOutsideDropArea: PropTypes.bool,

imageComponent: PropTypes.func,
fileComponent: PropTypes.func,
progressComponent: PropTypes.func,
Expand All @@ -22,6 +25,8 @@ export default class DropzoneS3Uploader extends React.Component {
PropTypes.func,
]),

childrenDropzone: PropTypes.node,

onDrop: PropTypes.func,
onError: PropTypes.func,
onProgress: PropTypes.func,
Expand All @@ -44,8 +49,9 @@ export default class DropzoneS3Uploader extends React.Component {
upload: {},
className: 'react-dropzone-s3-uploader',
passChildrenProps: true,
isImage: filename => filename && filename.match(/\.(jpeg|jpg|gif|png|svg)/i),
notDropzoneProps: ['onFinish', 's3Url', 'filename', 'host', 'upload', 'isImage', 'notDropzoneProps'],
s3Url: '',
isImage: fileName => fileName && fileName.match(/\.(jpeg|jpg|gif|png|svg)/i),
notDropzoneProps: ['onFinish', 'childrenDropzone', 'containerStyle', 'placeChildrenOutsideDropArea', 's3Url', 'fileName', 'host', 'upload', 'isImage', 'notDropzoneProps'],
style: {
width: 200,
height: 200,
Expand All @@ -68,11 +74,11 @@ export default class DropzoneS3Uploader extends React.Component {
constructor(props) {
super()
const uploadedFiles = []
const {filename} = props
if (filename) {
const {fileName} = props
if (fileName) {
uploadedFiles.push({
filename,
fileUrl: this.fileUrl(props.s3Url, filename),
fileName,
fileUrl: this.fileUrl(props.s3Url, fileName),
default: true,
file: {},
})
Expand All @@ -86,10 +92,8 @@ export default class DropzoneS3Uploader extends React.Component {
setUploaderOptions = props => {
this.setState({
uploaderOptions: Object.assign({
signingUrl: '/s3/sign',
s3path: '',
contentDisposition: 'auto',
uploadRequestHeaders: {'x-amz-acl': 'public-read'},
onFinishS3Put: this.handleFinish,
onProgress: this.handleProgress,
onError: this.handleError,
Expand All @@ -110,14 +114,15 @@ export default class DropzoneS3Uploader extends React.Component {
handleFinish = (info, file) => {
const uploadedFile = Object.assign({
file,
fileUrl: this.fileUrl(this.props.s3Url, info.filename),
fileUrl: this.fileUrl(this.props.s3Url, info.fileName || info.filename),
}, info)

const uploadedFiles = this.state.uploadedFiles
uploadedFiles.push(uploadedFile)
this.setState({uploadedFiles, error: null, progress: null}, () => {
this.props.onFinish && this.props.onFinish(uploadedFile)
})

this.props.onFinish && this.props.onFinish(uploadedFile)

this.setState({uploadedFiles, error: null, progress: null})
}

handleDrop = (files, rejectedFiles) => {
Expand All @@ -130,7 +135,7 @@ export default class DropzoneS3Uploader extends React.Component {
this.props.onDrop && this.props.onDrop(files, rejectedFiles)
}

fileUrl = (s3Url, filename) => `${s3Url.endsWith('/') ? s3Url.slice(0, -1) : s3Url}/${filename}`
fileUrl = (s3Url, fileName) => `${s3Url.endsWith('/') ? s3Url.slice(0, -1) : s3Url}/${fileName}`

renderImage = ({uploadedFile}) => (<div className="rdsu-image"><img src={uploadedFile.fileUrl} /></div>)

Expand Down Expand Up @@ -167,17 +172,29 @@ export default class DropzoneS3Uploader extends React.Component {
this.props.notDropzoneProps.forEach(prop => delete dropzoneProps[prop])

let content = null
let outsideContent = null

if (children) {
content = passChildrenProps ?
const childrenContent = passChildrenProps ?
React.Children.map(children, child => React.cloneElement(child, childProps)) :
this.props.children

if (this.props.placeChildrenOutsideDropArea) {
outsideContent = childrenContent

if (this.props.childrenDropzone) {
content = React.Children.map(this.props.childrenDropzone, child => React.cloneElement(child, childProps))
}
} else {
content = childrenContent
}
}
else {
content = (
<div>
{uploadedFiles.map(uploadedFile => {
const props = {
key: uploadedFile.filename,
key: uploadedFile.fileName,
uploadedFile: uploadedFile,
...childProps,
}
Expand All @@ -192,9 +209,12 @@ export default class DropzoneS3Uploader extends React.Component {
}

return (
<Dropzone ref={c => this._dropzone = c} onDrop={this.handleDrop} {...dropzoneProps}>
{content}
</Dropzone>
<div style={this.props.containerStyle}>
{outsideContent}
<Dropzone ref={c => this._dropzone = c} onDrop={this.handleDrop} {...dropzoneProps}>
{content}
</Dropzone>
</div>
)
}
}