mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-29 05:00:43 +10:00
Create FieldTextInput: Final Form version of TextInputField
This commit is contained in:
parent
fe7dedd43d
commit
63bd9aed65
6 changed files with 236 additions and 0 deletions
19
src/components/FieldTextInput/FieldTextInput.css
Normal file
19
src/components/FieldTextInput/FieldTextInput.css
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.root {
|
||||
}
|
||||
|
||||
.input {
|
||||
border-bottom-color: var(--attentionColor);
|
||||
}
|
||||
|
||||
.inputSuccess {
|
||||
border-bottom-color: var(--successColor);
|
||||
}
|
||||
|
||||
.inputError {
|
||||
border-bottom-color: var(--failColor);
|
||||
}
|
||||
|
||||
.textarea {
|
||||
}
|
||||
7
src/components/FieldTextInput/FieldTextInput.example.css
Normal file
7
src/components/FieldTextInput/FieldTextInput.example.css
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
.field {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.submit {
|
||||
margin-top: 24px;
|
||||
}
|
||||
90
src/components/FieldTextInput/FieldTextInput.example.js
Normal file
90
src/components/FieldTextInput/FieldTextInput.example.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* eslint-disable no-console */
|
||||
import React from 'react';
|
||||
import { Form as FinalForm, FormSpy } from 'react-final-form';
|
||||
import * as validators from '../../util/validators';
|
||||
import { Button } from '../../components';
|
||||
import FieldTextInput from './FieldTextInput';
|
||||
|
||||
import css from './FieldTextInput.example.css';
|
||||
|
||||
const FormComponent = props => (
|
||||
<FinalForm
|
||||
{...props}
|
||||
render={fieldRenderProps => {
|
||||
const { handleSubmit, onChange, invalid, pristine, submitting, formName } = fieldRenderProps;
|
||||
const required = validators.required('This field is required');
|
||||
const submitDisabled = invalid || pristine || submitting;
|
||||
return (
|
||||
<form
|
||||
onSubmit={e => {
|
||||
e.preventDefault();
|
||||
handleSubmit(e);
|
||||
}}
|
||||
>
|
||||
<FormSpy onChange={onChange} />
|
||||
<FieldTextInput
|
||||
className={css.field}
|
||||
type="text"
|
||||
id={`${formName}.input1`}
|
||||
name="input1"
|
||||
label="Input that requires a value:"
|
||||
validate={required}
|
||||
/>
|
||||
<FieldTextInput
|
||||
className={css.field}
|
||||
type="text"
|
||||
id={`${formName}.input2`}
|
||||
name="input2"
|
||||
label="Input that does not require a value:"
|
||||
/>
|
||||
<FieldTextInput
|
||||
className={css.field}
|
||||
type="text"
|
||||
name="input3"
|
||||
placeholder="Input without label..."
|
||||
/>
|
||||
<FieldTextInput
|
||||
className={css.field}
|
||||
type="textarea"
|
||||
id={`${formName}.textarea1`}
|
||||
name="textarea1"
|
||||
label="Textarea that requires a value:"
|
||||
validate={required}
|
||||
/>
|
||||
<FieldTextInput
|
||||
className={css.field}
|
||||
type="textarea"
|
||||
id={`${formName}.textarea2`}
|
||||
name="textarea2"
|
||||
label="Textarea that does not require a value:"
|
||||
/>
|
||||
<FieldTextInput
|
||||
className={css.field}
|
||||
type="textarea"
|
||||
name="textarea3"
|
||||
placeholder="Textarea without label..."
|
||||
/>
|
||||
<Button className={css.submit} type="submit" disabled={submitDisabled}>
|
||||
Submit
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const Inputs = {
|
||||
component: FormComponent,
|
||||
props: {
|
||||
formName: 'Inputs',
|
||||
onChange: formState => {
|
||||
if (Object.keys(formState.values).length > 0) {
|
||||
console.log('form values changed to:', formState.values);
|
||||
}
|
||||
},
|
||||
onSubmit: values => {
|
||||
console.log('submit values:', values);
|
||||
},
|
||||
},
|
||||
group: 'inputs',
|
||||
};
|
||||
117
src/components/FieldTextInput/FieldTextInput.js
Normal file
117
src/components/FieldTextInput/FieldTextInput.js
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* NOTE this component is part of react-final-form instead of Redux Form.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field } from 'react-final-form';
|
||||
import classNames from 'classnames';
|
||||
import { ValidationError, ExpandingTextarea } from '../../components';
|
||||
|
||||
import css from './FieldTextInput.css';
|
||||
|
||||
const CONTENT_MAX_LENGTH = 5000;
|
||||
|
||||
class FieldTextInputComponent extends Component {
|
||||
componentWillUnmount() {
|
||||
if (this.props.clearOnUnmount) {
|
||||
this.props.input.onChange('');
|
||||
}
|
||||
}
|
||||
render() {
|
||||
/* eslint-disable no-unused-vars */
|
||||
const {
|
||||
rootClassName,
|
||||
className,
|
||||
inputRootClass,
|
||||
clearOnUnmount,
|
||||
customErrorText,
|
||||
id,
|
||||
label,
|
||||
type,
|
||||
input,
|
||||
meta,
|
||||
...rest
|
||||
} = this.props;
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
if (label && !id) {
|
||||
throw new Error('id required when a label is given');
|
||||
}
|
||||
|
||||
const { valid, invalid, touched, error } = meta;
|
||||
const isTextarea = type === 'textarea';
|
||||
|
||||
const errorText = customErrorText || error;
|
||||
|
||||
// Error message and input error styles are only shown if the
|
||||
// field has been touched and the validation has failed.
|
||||
const hasError = touched && invalid && errorText;
|
||||
|
||||
const fieldMeta = { touched, error: errorText };
|
||||
|
||||
const inputClasses =
|
||||
inputRootClass ||
|
||||
classNames(css.input, {
|
||||
[css.inputSuccess]: valid,
|
||||
[css.inputError]: hasError,
|
||||
[css.textarea]: isTextarea,
|
||||
});
|
||||
const inputProps = isTextarea
|
||||
? { className: inputClasses, id, rows: 1, maxLength: CONTENT_MAX_LENGTH, ...input, ...rest }
|
||||
: { className: inputClasses, id, type, ...input, ...rest };
|
||||
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
return (
|
||||
<div className={classes}>
|
||||
{label ? <label htmlFor={id}>{label}</label> : null}
|
||||
{isTextarea ? <ExpandingTextarea {...inputProps} /> : <input {...inputProps} />}
|
||||
<ValidationError fieldMeta={fieldMeta} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FieldTextInputComponent.defaultProps = {
|
||||
rootClassName: null,
|
||||
className: null,
|
||||
inputRootClass: null,
|
||||
clearOnUnmount: false,
|
||||
customErrorText: null,
|
||||
id: null,
|
||||
label: null,
|
||||
};
|
||||
|
||||
const { string, bool, shape, func, object } = PropTypes;
|
||||
|
||||
FieldTextInputComponent.propTypes = {
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
inputRootClass: string,
|
||||
|
||||
clearOnUnmount: bool,
|
||||
|
||||
// Error message that can be manually passed to input field,
|
||||
// overrides default validation message
|
||||
customErrorText: string,
|
||||
|
||||
// Label is optional, but if it is given, an id is also required so
|
||||
// the label can reference the input in the `for` attribute
|
||||
id: string,
|
||||
label: string,
|
||||
|
||||
// Either 'textarea' or something that is passed to the input element
|
||||
type: string.isRequired,
|
||||
|
||||
// Generated by redux-form's Field component
|
||||
input: shape({
|
||||
onChange: func.isRequired,
|
||||
}).isRequired,
|
||||
meta: object.isRequired,
|
||||
};
|
||||
|
||||
const FieldTextInput = props => {
|
||||
return <Field component={FieldTextInputComponent} {...props} />;
|
||||
};
|
||||
|
||||
export default FieldTextInput;
|
||||
|
|
@ -38,6 +38,7 @@ export { default as FieldDateRangeInput } from './FieldDateRangeInput/FieldDateR
|
|||
export { default as FieldGroupCheckbox } from './FieldGroupCheckbox/FieldGroupCheckbox';
|
||||
export { default as FieldPhoneNumberInput } from './FieldPhoneNumberInput/FieldPhoneNumberInput';
|
||||
export { default as FieldReviewRating } from './FieldReviewRating/FieldReviewRating';
|
||||
export { default as FieldTextInput } from './FieldTextInput/FieldTextInput';
|
||||
export { default as Footer } from './Footer/Footer';
|
||||
export { default as Form } from './Form/Form';
|
||||
export { default as IconBannedUser } from './IconBannedUser/IconBannedUser';
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import * as FieldDateRangeInput from './components/FieldDateRangeInput/FieldDate
|
|||
import * as FieldGroupCheckbox from './components/FieldGroupCheckbox/FieldGroupCheckbox.example';
|
||||
import * as FieldPhoneNumberInput from './components/FieldPhoneNumberInput/FieldPhoneNumberInput.example';
|
||||
import * as FieldReviewRating from './components/FieldReviewRating/FieldReviewRating.example';
|
||||
import * as FieldTextInput from './components/FieldTextInput/FieldTextInput.example';
|
||||
import * as Footer from './components/Footer/Footer.example';
|
||||
import * as IconBannedUser from './components/IconBannedUser/IconBannedUser.example';
|
||||
import * as IconCheckmark from './components/IconCheckmark/IconCheckmark.example';
|
||||
|
|
@ -104,6 +105,7 @@ export {
|
|||
FieldGroupCheckbox,
|
||||
FieldPhoneNumberInput,
|
||||
FieldReviewRating,
|
||||
FieldTextInput,
|
||||
Footer,
|
||||
IconBannedUser,
|
||||
IconCheckmark,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue