diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-07-22 14:05:15 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-07-22 14:05:15 +0200 |
| commit | ef78bc6a084f92b4794e987b5832240d85b6479e (patch) | |
| tree | b314b630800db6aa60f28ef0b115625e6ca176db /animism-align/frontend/app/common/form.component.js | |
| parent | 85d4cb9addf9ca887d3440b2786665d67d9917c4 (diff) | |
refactor app using babel module-resolver
Diffstat (limited to 'animism-align/frontend/app/common/form.component.js')
| -rw-r--r-- | animism-align/frontend/app/common/form.component.js | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/animism-align/frontend/app/common/form.component.js b/animism-align/frontend/app/common/form.component.js new file mode 100644 index 0000000..c727544 --- /dev/null +++ b/animism-align/frontend/app/common/form.component.js @@ -0,0 +1,222 @@ +import React, { Component } from 'react' +import { courtesyS } from 'app/utils' + +export const TextInput = props => ( + <label className={props.error ? 'error' : 'text'}> + {props.title && <span>{props.title}</span>} + <input + type="text" + required={props.required} + onChange={props.onChange} + onBlur={props.onBlur} + name={props.name} + value={props.data[props.name] || ""} + placeholder={props.placeholder} + autoComplete={props.autoComplete} + /> + </label> +) + +export const LabelDescription = props => ( + <label className={props.className ? 'text description ' + props.className : 'text description'}> + <span>{props.title}</span> + <span>{props.children}</span> + </label> +) + +export const NumberInput = props => ( + <label className={props.error ? 'error' : 'text'}> + <span>{props.title}</span> + <input + type="number" + required={props.required} + onChange={props.onChange} + name={props.name} + value={props.data[props.name]} + min={props.min} + max={props.max} + step={props.step || 1} + /> + </label> +) + +export const ColorInput = props => ( + <label className={props.error ? 'error color' : 'text color'}> + <span>{props.title}</span> + <input + type="color" + required={props.required} + onChange={props.onChange} + name={props.name} + value={props.data[props.name]} + /> + <input + type="text" + required={props.required} + onChange={props.onChange} + name={props.name} + value={props.data[props.name]} + /> + </label> +) + +export const TextArea = props => ( + <label className={props.error ? 'textarea error' : 'textarea'}> + {props.title && <span>{props.title}</span>} + <textarea + onChange={props.onChange} + name={props.name} + placeholder={props.placeholder} + value={props.data[props.name]} + /> + </label> +) + +export const Checkbox = props => ( + <label className="checkbox"> + <input + type="checkbox" + name={props.name} + value={1} + checked={props.checked} + onChange={(e) => props.onChange(props.name, e.target.checked)} + /> + <span>{props.label}</span> + </label> +) + +export const Radio = props => { + return ( + <label className="radio"> + <input + type="radio" + name={props.name} + value={props.value} + checked={props.value === props.currentValue} + onChange={() => props.onChange(props.name, props.value)} + /> + <span>{props.label}</span> + </label> + ) +} + +export class Select extends Component { + state = { + focused: false, + } + + render() { + const { name, selected, options, defaultOption, title, loading, onChange, className } = this.props + if (loading) { + return <label className='select'><div>Loading...</div></label> + } + const { focused } = this.state + return ( + <label> + {title && <span>{title}</span>} + <div className={(focused ? 'select focus' : 'select') + " " + (className || "")}> + <div>{(options.find(opt => String(opt.name) === String(selected)) || {label: defaultOption}).label}</div> + <select + onFocus={() => this.setState({ focused: true })} + onBlur={() => this.setState({ focused: false })} + onChange={e => { + onChange(name, e.target.value) + // this.setState({ focused: false }) + }} + value={selected || "__default__"} + > + {!selected && defaultOption && <option value="__default__">{defaultOption}</option>} + {options.map((option, i) => ( + <option + key={option.name} + value={option.name} + disabled={option.disabled} + >{option.label}</option> + ))} + </select> + </div> + </label> + ) + } +} + +export class FileInputField extends Component { + state = { + count: 0, + } + + handleChange(files) { + const { multiple, onChange } = this.props + if (!files) { + this.setState({ count: 0 }) + } else { + this.setState({ count: multiple ? files.length : 0 }) + } + onChange(files) + } + + render() { + const { error, title, label, required, multiple, mime, name } = this.props + return ( + <label className={error ? 'error' : 'text fileInput'}> + <span>{title}</span> + <div className="row"> + <button> + {label || (multiple ? "Choose files" : "Choose file")} + <FileInput + mime={mime} + multiple={multiple} + onChange={this.handleChange.bind(this)} + /> + </button> + {!!this.state.count && <span>{courtesyS(this.state.count, "file")}{" selected"}</span>} + </div> + </label> + ) + } +} + +export class FileInput extends Component { + handleChange(e) { + let { multiple, mime } = this.props + if (!mime) { + mime = "image/" + } + const files = e.dataTransfer ? e.dataTransfer.files : e.target.files + let i + let file, selectedFiles = [] + for (i = 0; i < files.length; i++) { + file = files[i] + if (file && file.type.indexOf(mime) === 0) { + if (multiple) { + selectedFiles.push(file) + } else { + break + } + } + } + if (multiple && selectedFiles.length) { + this.props.onChange(selectedFiles) + } else if (!multiple && file) { + this.props.onChange(file) + } else { + this.props.onChange() + } + } + + render() { + return ( + <input type="file" multiple={!!this.props.multiple} onChange={this.handleChange.bind(this)} /> + ) + } +} + +export const SubmitButton = (props) => ( + <label> + <span></span> + <button + className={props.className ? "submit " + props.className : "submit"} + onClick={props.onClick} + >{props.title}</button> + </label> +) |
