Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-files

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-files - npm Package Compare versions

Comparing version 1.1.1 to 2.0.0

.eslintrc.js

10

package.json
{
"name": "react-files",
"version": "1.1.1",
"version": "2.0.0",
"main": "src/Files.js",

@@ -40,4 +40,8 @@ "description": "A file input (dropzone) management component for React",

"babel-preset-stage-0": "6.0.15",
"eslint": "1.10.3",
"eslint-plugin-react": "3.6.2",
"eslint": "3.4.0",
"eslint-config-standard": "6.0.0",
"eslint-config-standard-react": "4.0.0",
"eslint-plugin-promise": "2.0.1",
"eslint-plugin-react": "6.2.0",
"eslint-plugin-standard": "2.0.0",
"expect": "1.20.2",

@@ -44,0 +48,0 @@ "expect-jsx": "2.6.0",

@@ -14,3 +14,3 @@ react-files

```
```bash
npm install react-files --save

@@ -21,2 +21,4 @@ ```

#### Basic
```js

@@ -28,7 +30,7 @@ import React from 'react'

var FilesDemo = React.createClass({
onSubmit: function(files) {
onFilesChange: function (files) {
console.log(files)
},
onError: function(error, file) {
onFilesError: function (error, file) {
console.log('error code ' + error.code + ': ' + error.message)

@@ -41,8 +43,14 @@ },

<Files
onSubmit={this.onSubmit}
onError={this.onError}
maxFiles={10}
maxSize={10000000}
minSize={1000}
/>
className='files-dropzone'
onChange={this.onFilesChange}
onError={this.onFilesError}
accepts={['image/png', 'text/plain', 'audio/*']}
multiple
maxFiles={3}
maxFileSize={10000000}
minFileSize={0}
clickable
>
Drop files here or click to upload
</Files>
</div>

@@ -56,7 +64,20 @@ )

### Props
#### Advanced
See "Tinker" instructions below to run and view all examples.
> `onSubmit(files)` - Function
### Tinker
```
git clone https://github.com/mother/react-files
npm install
npm start
```
Then visit http://localhost:8000/
## Props
`onChange(files)` - *Function*
Perform work on files added when submit is clicked.

@@ -66,8 +87,6 @@

> `onError(error, file)` - Function
`onError(error, file)` - *Function*
- `error.code` - Number
- `error.message` - String
`error.code` - Number
`error.message` - String
Perform work or notify the user when an error occurs.

@@ -83,9 +102,11 @@

> `accepts` - Array of String
`accepts` - *Array* of *String*
Control what types of generic/specific MIME types, or specific extensions can be dropped/added.
Control what types of generic/specific MIME types, can be dropped/added.
Example
> See full list of MIME types here: http://www.iana.org/assignments/media-types/media-types.xhtml
Example:
```js
accepts={['image/*', 'video/mp4', 'audio/*', '.pdf', '.txt']}
accepts={['image/*', 'video/mp4', 'audio/*']}
```

@@ -95,4 +116,22 @@

> `maxFiles` - Number
`multiple` - *Boolean*
Default: `true`
Allow multiple files
---
`clickable` - *Boolean*
Default: `true`
Dropzone is clickable to open file browser. Disable for dropping only.
---
`maxFiles` - *Number*
Default: `Infinity`
Maximum number of files allowed

@@ -102,4 +141,6 @@

> `maxSize` - Number
`maxFileSize` - *Number*
Default: `Infinity`
Maximum file size allowed (in bytes)

@@ -109,4 +150,6 @@

> `minSize` - Number
`minFileSize` - *Number*
Default: `0`
Minimum file size allowed (in bytes)

@@ -116,29 +159,10 @@

### Styling
`dropActiveClassName` - *String*
Be sure to style your Files component, available selectors are (view `style.css`):
- .files-container
- .files-dropzone-outer
- .files-dropzone
- .files-dropzone:before
- .files-dropzone-ondragenter
- .files-buttons
- .files-button-submit
- .files-button-submit:before
- .files-button-clear
- .files-button-clear:before
- .files-list
- .files-list ul
- .files-list li:last-child
- .files-list-item
- .files-list-item-content
- .files-list-item-content-item
- .files-list-item-content-item-1
- .files-list-item-content-item-2
- .files-list-item-preview
- .files-list-item-preview-image
- .files-list-item-preview-extension
- .files-list-item-remove
- .files-list-item-remove-image
Default: `'files-dropzone-active'`
Class added to the Files component when user is actively hovering over the dropzone with files selected.
---
### Test (todo)

@@ -150,12 +174,4 @@

### Tinker
```
git clone https://github.com/mother/react-files
npm install
npm start
```
### License
MIT. Copyright (c) 2016 Jared Reich.
import React from 'react'
class Files extends React.Component {
constructor(props, context) {
constructor (props, context) {
super(props, context)
this.onDrop = this.onDrop.bind(this)
this.onSubmit = this.onSubmit.bind(this)
this.onClear = this.onClear.bind(this)
this.onDragEnter = this.onDragEnter.bind(this)
this.onDragLeave = this.onDragLeave.bind(this)
this.openFileChooser = this.openFileChooser.bind(this)

@@ -18,3 +18,3 @@

onDrop(event) {
onDrop (event) {
event.preventDefault()

@@ -25,3 +25,9 @@ this.onDragLeave(event)

// then return to method
const filesAdded = event.dataTransfer ? event.dataTransfer.files : event.target.files
let filesAdded = event.dataTransfer ? event.dataTransfer.files : event.target.files
// Multiple files dropped when not allowed
if (this.props.multiple === false && filesAdded.length > 1) {
filesAdded = [filesAdded[0]]
}
let files = []

@@ -32,4 +38,10 @@ for (let i = 0; i < filesAdded.length; i++) {

// Assign file an id
file.id = 'files-list-item-' + this.id++
file.id = 'files-' + this.id++
// Tell file it's own extension
file.extension = this.fileExtension(file)
// Tell file it's own readable size
file.sizeReadable = this.fileSizeReadable(file.size)
// Add preview, either image or file extension

@@ -43,4 +55,3 @@ if (file.type && this.mimeTypeLeft(file.type) === 'image') {

file.preview = {
type: 'file',
extension: this.fileExtension(file)
type: 'file'
}

@@ -52,4 +63,4 @@ }

this.onError({
code: 4,
message: 'maximum file count reached'
code: 4,
message: 'maximum file count reached'
}, file)

@@ -59,10 +70,17 @@ break

// If file is acceptable, unshift
if (this.fileTypeAcceptable(file) &&
this.fileSizeAcceptable(file)) files.unshift(file)
// If file is acceptable, push or replace
if (this.fileTypeAcceptable(file) && this.fileSizeAcceptable(file)) {
files.push(file)
}
}
this.setState({ files: [...files, ...this.state.files] })
this.setState({
files: this.props.multiple === false
? files
: [...this.state.files, ...files]
}, () => {
this.props.onChange.call(this, this.state.files)
})
}
onDragOver(event) {
onDragOver (event) {
event.preventDefault()

@@ -72,11 +90,13 @@ event.stopPropagation()

onDragEnter(event) {
event.target.className += ' files-dropzone-ondragenter'
onDragEnter (event) {
let el = document.getElementsByClassName(this.props.className)[0]
el.className += ' ' + this.props.dropActiveClassName
}
onDragLeave(event) {
event.target.className = event.target.className.replace(' files-dropzone-ondragenter', '')
onDragLeave (event) {
let el = document.getElementsByClassName(this.props.className)[0]
el.className = el.className.replace(' ' + this.props.dropActiveClassName, '')
}
openFileChooser() {
openFileChooser () {
this.inputElement.value = null

@@ -86,12 +106,5 @@ this.inputElement.click()

removeFile(fileId) {
this.setState({
files: this.state.files.filter(file => file.id !== fileId)
})
}
fileTypeAcceptable(file) {
let accepts = this.props.accepts
fileTypeAcceptable (file) {
let accepts = this.props.accepts
if (accepts) {
if (accepts.indexOf(this.fileExtension(file)) !== -1) return true
if (file.type) {

@@ -115,4 +128,4 @@ let typeLeft = this.mimeTypeLeft(file.type)

this.onError({
code: 1,
message: file.name + ' is not a valid file type'
code: 1,
message: file.name + ' is not a valid file type'
}, file)

@@ -125,13 +138,13 @@ return false

fileSizeAcceptable(file) {
if (file.size > this.props.maxSize) {
fileSizeAcceptable (file) {
if (file.size > this.props.maxFileSize) {
this.onError({
code: 2,
message: file.name + ' is too large'
code: 2,
message: file.name + ' is too large'
}, file)
return false
} else if (file.size < this.props.minSize) {
} else if (file.size < this.props.minFileSize) {
this.onError({
code: 3,
message: file.name + ' is too small'
code: 3,
message: file.name + ' is too small'
}, file)

@@ -144,14 +157,14 @@ return false

mimeTypeLeft(mime) {
mimeTypeLeft (mime) {
return mime.split('/')[0]
}
mimeTypeRight(mime) {
mimeTypeRight (mime) {
return mime.split('/')[1]
}
fileExtension(file) {
fileExtension (file) {
let extensionSplit = file.name.split('.')
if (extensionSplit.length > 1) {
return '.' + extensionSplit[extensionSplit.length - 1]
return extensionSplit[extensionSplit.length - 1]
} else {

@@ -162,3 +175,3 @@ return 'none'

fileSizeReadable(size) {
fileSizeReadable (size) {
if (size >= 1000000000) {

@@ -175,23 +188,31 @@ return Math.ceil(size / 1000000000) + 'GB'

onSubmit() {
this.props.onSubmit.call(this, this.state.files)
onError (error, file) {
this.props.onError.call(this, error, file)
}
onError(error, file) {
this.props.onError.call(this, error, file)
removeFile (fileToRemove) {
this.setState({
files: this.state.files.filter(file => file.id !== fileToRemove.id)
}, () => {
this.props.onChange.call(this, this.state.files)
})
}
onClear() {
removeFiles () {
this.setState({
files: []
}, () => {
this.props.onChange.call(this, this.state.files)
})
}
render() {
render () {
const inputAttributes = {
type: 'file',
multiple: true,
accept: this.props.accepts ? this.props.accepts.join() : '',
multiple: this.props.multiple ? this.props.multiple : true,
style: { display: 'none' },
ref: element => this.inputElement = element,
ref: (element) => {
this.inputElement = element
},
onChange: this.onDrop

@@ -201,53 +222,20 @@ }

return (
<div
className="files-container"
>
<div>
<input
// {...inputProps/* expand user provided inputProps first so inputAttributes override them */}
{...inputAttributes}
/>
<div
className="files-dropzone-outer"
<div className={this.props.className}
onClick={
this.props.clickable === true
? this.openFileChooser
: null
}
onDrop={this.onDrop}
onDragOver={this.onDragOver}
onDragEnter={this.onDragEnter}
onDragLeave={this.onDragLeave}
>
<div className="files-dropzone"
onClick={this.openFileChooser}
onDrop={this.onDrop}
onDragOver={this.onDragOver}
onDragEnter={this.onDragEnter}
onDragLeave={this.onDragLeave}
/>
{this.props.children}
</div>
{this.props.children}
{
this.state.files.length > 0
? <div>
<div className="files-list">
<ul>{this.state.files.map((file) =>
<li className="files-list-item" key={file.id}>
<div className="files-list-item-preview">
{file.preview.type === 'image'
? <img className="files-list-item-preview-image" src={file.preview.url} />
: <div className="files-list-item-preview-extension">{file.preview.extension}</div>}
</div>
<div className="files-list-item-content">
<div className="files-list-item-content-item files-list-item-content-item-1">{file.name}</div>
<div className="files-list-item-content-item-2 files-list-item-content-item-2" className="files-list-item-content-item">{this.fileSizeReadable(file.size)}</div>
</div>
<div
id={file.id}
className="files-list-item-remove"
onClick={this.removeFile.bind(this, file.id)}
/>
</li>
)}</ul>
</div>
<div className="files-buttons">
<div onClick={this.onSubmit} className="files-button-submit" />
<div onClick={this.onClear} className="files-button-clear" />
</div>
</div>
: null
}
</div>
)

@@ -258,21 +246,33 @@ }

Files.propTypes = {
onSubmit: React.PropTypes.func.isRequired,
onError: React.PropTypes.func.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.node),
React.PropTypes.node
]),
className: React.PropTypes.string.isRequired,
dropActiveClassName: React.PropTypes.string,
onChange: React.PropTypes.func,
onError: React.PropTypes.func,
accepts: React.PropTypes.array,
multiple: React.PropTypes.bool,
maxFiles: React.PropTypes.number,
maxSize: React.PropTypes.number,
minSize: React.PropTypes.number
maxFileSize: React.PropTypes.number,
minFileSize: React.PropTypes.number,
clickable: React.PropTypes.bool
}
Files.defaultProps = {
onSubmit: function (files) {
console.log(files)
},
onError: function (error, file) {
console.log('error code ' + error.code + ': ' + error.message)
},
maxFiles: Infinity,
maxSize: Infinity,
minSize: 0
onChange: function (files) {
console.log(files)
},
onError: function (error, file) {
console.log('error code ' + error.code + ': ' + error.message)
},
dropActiveClassName: 'files-dropzone-active',
multiple: true,
maxFiles: Infinity,
maxFileSize: Infinity,
minFileSize: 0,
clickable: true
}
export default Files

@@ -5,21 +5,76 @@ import React from 'react'

var FilesDemo = React.createClass({
onSubmit: function(files) {
console.log(files)
var FilesDemo1 = React.createClass({
getInitialState () {
return {
files: []
}
},
onError: function(error, file) {
onFilesChange: function (files) {
this.setState({
files
}, () => {
console.log(this.state.files)
})
},
onFilesError: function (error, file) {
console.log('error code ' + error.code + ': ' + error.message)
},
render: function() {
filesRemoveOne: function (file) {
this.refs.files.removeFile(file)
},
filesRemoveAll: function () {
this.refs.files.removeFiles()
},
filesUpload: function () {
window.alert('Ready to upload ' + this.state.files.length + ' file(s)!')
},
render: function () {
return (
<div className="files">
<div>
<h1>Example 1 - List</h1>
<Files
onSubmit={this.onSubmit}
onError={this.onError}
ref='files'
className='files-dropzone-list'
onChange={this.onFilesChange}
onError={this.onFilesError}
multiple
maxFiles={10}
maxSize={10000000}
minSize={1000}
/>
maxFileSize={10000000}
minFileSize={0}
clickable
>
Drop files here or click to upload
</Files>
<button onClick={this.filesRemoveAll}>Remove All Files</button>
<button onClick={this.filesUpload}>Upload</button>
{
this.state.files.length > 0
? <div className='files-list'>
<ul>{this.state.files.map((file) =>
<li className='files-list-item' key={file.id}>
<div className='files-list-item-preview'>
{file.preview.type === 'image'
? <img className='files-list-item-preview-image' src={file.preview.url} />
: <div className='files-list-item-preview-extension'>{file.extension}</div>}
</div>
<div className='files-list-item-content'>
<div className='files-list-item-content-item files-list-item-content-item-1'>{file.name}</div>
<div className='files-list-item-content-item files-list-item-content-item-2'>{file.sizeReadable}</div>
</div>
<div
id={file.id}
className='files-list-item-remove'
onClick={this.filesRemoveOne.bind(this, file)} // eslint-disable-line
/>
</li>
)}</ul>
</div>
: null
}
</div>

@@ -30,2 +85,54 @@ )

ReactDOM.render(<FilesDemo />, document.getElementById('container'))
var FilesDemo2 = React.createClass({
getInitialState () {
return {
files: []
}
},
onFilesChange: function (files) {
this.setState({
files
}, () => {
console.log(this.state.files)
})
},
onFilesError: function (error, file) {
console.log('error code ' + error.code + ': ' + error.message)
},
filesRemoveAll: function () {
this.refs.files.removeFiles()
},
render: function () {
return (
<div>
<h1>Example 2 - Gallery</h1>
<Files
ref='files'
className='files-dropzone-gallery'
onChange={this.onFilesChange}
onError={this.onFilesError}
accepts={['image/*']}
multiple
clickable={false}
>
{
this.state.files.length > 0
? <div className='files-gallery'>
{this.state.files.map((file) =>
<img className='files-gallery-item' src={file.preview.url} key={file.id} />
)}
</div>
: <div>Drop images here</div>
}
</Files>
<button onClick={this.filesRemoveAll}>Remove All Files</button>
</div>
)
}
})
ReactDOM.render(<div><FilesDemo1 /><FilesDemo2 /></div>, document.getElementById('container'))

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc