-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Haofu Zhu
committed
Sep 9, 2020
1 parent
5a95fbc
commit 8f1f580
Showing
6 changed files
with
275 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,169 @@ | ||
import classNames from 'classnames'; | ||
import _ from 'lodash'; | ||
import PropTypes from 'prop-types'; | ||
import React from 'react'; | ||
import React, { useState, useRef } from 'react'; | ||
import Button from 'react-bootstrap/lib/Button'; | ||
import './styles.scss'; | ||
|
||
const baseClass = 'filepicker-component'; | ||
const baseClass = 'aui--filepicker-component'; | ||
|
||
class FilePickerComponent extends React.PureComponent { | ||
static propTypes = { | ||
/** | ||
* determines if the filePicker is disabled | ||
*/ | ||
disabled: PropTypes.bool, | ||
/** | ||
* data-test-selector of the filePicker | ||
*/ | ||
dts: PropTypes.string, | ||
/** | ||
* determines what file types the user can pick from the file input dialog box | ||
*/ | ||
filter: PropTypes.string, | ||
/** | ||
* determines if the filePicker is highlighted or not | ||
*/ | ||
isHighlighted: PropTypes.bool, | ||
/** | ||
* the label to be displayed | ||
*/ | ||
label: PropTypes.string, | ||
/** | ||
* function called when onRemove event is fired | ||
*/ | ||
onRemove: PropTypes.func, | ||
/** | ||
* function called when onSelect event is fired | ||
*/ | ||
onSelect: PropTypes.func.isRequired, | ||
/** | ||
* determines the placeholder when no date is selected | ||
*/ | ||
placeholder: PropTypes.string, | ||
}; | ||
|
||
static defaultProps = { | ||
isHighlighted: false, | ||
label: 'Select', | ||
placeholder: 'No file selected', | ||
disabled: false, | ||
}; | ||
|
||
constructor(props) { | ||
super(props); | ||
|
||
this.fileInput = React.createRef(); | ||
} | ||
const FilePickerComponent = ({ | ||
disabled, | ||
dts, | ||
filter, | ||
isHighlighted, | ||
label, | ||
onRemove, | ||
onSelect, | ||
onClick, | ||
onChange, | ||
value, | ||
placeholder, | ||
}) => { | ||
const [isFileSelected, setIsFileSelected] = useState(false); | ||
const [fileName, setFileName] = useState(''); | ||
const fileInput = useRef(); | ||
|
||
state = { | ||
isFileSelected: false, | ||
fileName: '', | ||
}; | ||
const selectFile = event => { | ||
if (!isFileSelected) { | ||
const file = event.target.files[0]; | ||
setIsFileSelected(true); | ||
if (_.isFunction(onChange)) { | ||
onChange(file.name); | ||
} | ||
setFileName(file.name); | ||
|
||
onChange = changeEvent => { | ||
if (!this.state.isFileSelected) { | ||
this.setState({ isFileSelected: true, fileName: changeEvent.target.files[0].name }); | ||
this.props.onSelect(changeEvent.target.files[0]); | ||
onSelect(file); | ||
} | ||
}; | ||
|
||
onUploadBtnClick = () => { | ||
this.fileInput.current.click(); | ||
const onUploadBtnClick = () => { | ||
fileInput.current.click(); | ||
}; | ||
|
||
removeFile = () => { | ||
if (this.state.isFileSelected) { | ||
this.fileInput.current.value = null; | ||
this.setState({ isFileSelected: false, fileName: '' }); | ||
if (this.props.onRemove) { | ||
this.props.onRemove(); | ||
const removeFile = () => { | ||
if (isFileSelected || !_.isEmpty(value)) { | ||
fileInput.current.value = null; | ||
setIsFileSelected(false); | ||
if (_.isFunction(onChange)) { | ||
onChange(''); | ||
} | ||
setFileName(''); | ||
|
||
if (_.isFunction(onRemove)) { | ||
onRemove(); | ||
} | ||
} | ||
}; | ||
|
||
render() { | ||
const mainClass = classNames({ [`${baseClass}-highlight`]: this.props.isHighlighted }, baseClass, 'input-group'); | ||
const { isFileSelected, fileName } = this.state; | ||
const clickFile = () => { | ||
if (_.isFunction(onClick)) { | ||
onClick(); | ||
} | ||
}; | ||
|
||
if (value && !onChange) | ||
console.warn( | ||
'Failed prop type: You have provided a `value` prop to FilePicker Component without an `onChange` handler. This will render a read-only field.' | ||
); | ||
|
||
return ( | ||
<div data-testid="file-picker-wrapper" className={mainClass}> | ||
<input | ||
data-testid="file-picker-form-control" | ||
className="form-control" | ||
type="text" | ||
disabled | ||
placeholder={this.props.placeholder} | ||
readOnly="readonly" | ||
value={fileName} | ||
title={fileName} | ||
/> | ||
<div className="input-group-btn"> | ||
{isFileSelected ? ( | ||
<Button data-testid="file-picker-remove-button" className="remove-file" onClick={this.removeFile}> | ||
× | ||
</Button> | ||
) : null} | ||
<Button | ||
data-testid="file-picker-input-button" | ||
className="btn-inverse" | ||
onClick={this.onUploadBtnClick} | ||
disabled={this.props.disabled || isFileSelected} | ||
> | ||
<span data-testid="file-picker-input-button-label">{this.props.label}</span> | ||
<input | ||
data-testid="file-picker-input-button-input" | ||
className="file-input" | ||
ref={this.fileInput} | ||
type="file" | ||
onChange={this.onChange} | ||
accept={this.props.filter} | ||
data-test-selector={this.props.dts} | ||
/> | ||
const hasFileName = _.isString(value) ? value !== '' : isFileSelected; | ||
|
||
return ( | ||
<div | ||
className={classNames({ [`${baseClass}-highlight`]: isHighlighted }, baseClass, 'input-group')} | ||
data-test-selector={dts} | ||
data-testid="file-picker-wrapper" | ||
> | ||
<input | ||
data-testid="file-picker-form-control" | ||
className={classNames('form-control', { clickable: _.isFunction(onClick) })} | ||
type="text" | ||
readOnly | ||
placeholder={placeholder} | ||
value={value || fileName} | ||
title={value || fileName} | ||
onClick={clickFile} | ||
/> | ||
<div className="input-group-btn"> | ||
{hasFileName ? ( | ||
<Button data-testid="file-picker-remove-button" className="remove-file" onClick={removeFile}> | ||
× | ||
</Button> | ||
</div> | ||
) : null} | ||
<Button | ||
data-testid="file-picker-input-button" | ||
className="btn-inverse select-file" | ||
onClick={onUploadBtnClick} | ||
disabled={disabled || hasFileName} | ||
> | ||
<span data-testid="file-picker-input-button-label">{label}</span> | ||
<input | ||
data-testid="file-picker-input-button-input" | ||
className="file-input" | ||
ref={fileInput} | ||
type="file" | ||
onChange={selectFile} | ||
accept={filter} | ||
/> | ||
</Button> | ||
</div> | ||
); | ||
} | ||
} | ||
</div> | ||
); | ||
}; | ||
|
||
FilePickerComponent.propTypes = { | ||
/** | ||
* determines if the filePicker is disabled | ||
*/ | ||
disabled: PropTypes.bool, | ||
/** | ||
* data-test-selector of the filePicker | ||
*/ | ||
dts: PropTypes.string, | ||
/** | ||
* determines what file types the user can pick from the file input dialog box | ||
*/ | ||
filter: PropTypes.string, | ||
/** | ||
* determines if the filePicker is highlighted or not | ||
*/ | ||
isHighlighted: PropTypes.bool, | ||
/** | ||
* label on button | ||
*/ | ||
label: PropTypes.string, | ||
/** | ||
* function called when onRemove event is fired | ||
*/ | ||
onRemove: PropTypes.func, | ||
/** | ||
* function called when onSelect event is fired | ||
*/ | ||
onSelect: PropTypes.func.isRequired, | ||
/** | ||
* function called when user click the file name | ||
*/ | ||
onClick: PropTypes.func, | ||
/** | ||
* function called when the file name changes | ||
*/ | ||
onChange: PropTypes.func, | ||
/** | ||
* file name on input | ||
*/ | ||
value: PropTypes.string, | ||
/** | ||
* determines the placeholder when no date is selected | ||
*/ | ||
placeholder: PropTypes.string, | ||
}; | ||
|
||
FilePickerComponent.defaultProps = { | ||
isHighlighted: false, | ||
label: 'Select', | ||
placeholder: 'No file selected', | ||
disabled: false, | ||
}; | ||
|
||
export default FilePickerComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.