Skip to content

Commit

Permalink
feat: adding text field multiline
Browse files Browse the repository at this point in the history
  • Loading branch information
CesarBenavides777 committed Mar 6, 2021
1 parent b5238c7 commit 472a30d
Show file tree
Hide file tree
Showing 8 changed files with 416 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .jest-test-results.json

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions src/components/FormFields/TextFieldMultiline/TextFieldMultiline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useField } from 'formik';
import TextareaAutosize from 'react-textarea-autosize';
import { Label } from '../Label';
import { HelperText } from '../HelperText';
import { Icon } from '../../Icon';
import { IconButton } from '../../IconButton';
import './TextFieldMultiline.scss';

const TextFieldMultiline = ({
addClass,
autoComplete,
children,
domId,
helperText,
hideLabel,
icon,
iconPos,
iconOnClick,
iconSR, // screen reader text for icon
label,
maxLength,
required,
storybookErrorPreview, // For storybook only
type,
minRows,
maxRows,
onChange,
...props
}) => {
// useField passes name, placeholder, value, onChange and onBlur
const [field, meta] = useField({ ...props, type: 'text' });
const error = !!(meta.touched && meta.error && typeof meta.error === 'string') || storybookErrorPreview;
const fieldHelperText = error ? meta.error : helperText;

// eslint-disable-next-line react/destructuring-assignment
const [value, setValue] = useState(props.value || '');

const onValueChange = (event) => {
setValue(event.target.value)
onChange(event)
}

const classes = classNames(
'input-field-container',
'input-field-text',
{ 'no-helpertext': !fieldHelperText },
hideLabel && 'hidden-label',
iconPos && `has-icon icon-${iconPos}`,
addClass,
{ error },
);

const wrapperClasses = classNames(
'input-field',
'textarea-wrapper',
{ error },
);

const inputClasses = classNames(
'input-field-textarea',
{ error },
)
const InputIcon = () => (
<>
{iconOnClick ?
<IconButton icon={icon} size={24} click={iconOnClick}>{iconSR}</IconButton> :
<Icon name={icon} size={24} error={error || storybookErrorPreview} />}
</>
);
// IMPORTANT: props and field should be speaded before the value and onChange,
// field contains default onChange from formik which will override the defined onValueChange
return (
<div className={classes} data-testid="test-id-input">
<div className={wrapperClasses}>
<TextareaAutosize
className={inputClasses}
autoComplete={autoComplete}
error={(error || storybookErrorPreview || false).toString()}
maxLength={maxLength}
required={required}
type={type}
minRows={minRows}
maxRows={maxRows}
// Spreading props, as required by Formik in useField: https://jaredpalmer.com/formik/docs/api/useField#example
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
// eslint-disable-next-line react/jsx-props-no-spreading
{...field}
value={value}
onChange={onValueChange}
/>
</div>
{children}
<Label
color="gray4"
display="block"
fieldType="text"
forId={domId}
hideLabel={hideLabel}
required={required}
>
{label}
</Label>
{iconPos && <InputIcon />}
{
fieldHelperText && (
<HelperText error={error || storybookErrorPreview}>
{fieldHelperText}
</HelperText>
)
}
</div >
);
};

TextFieldMultiline.defaultProps = {
iconOnClick: null,
};

TextFieldMultiline.propTypes = {
addClass: PropTypes.string,
autoComplete: PropTypes.oneOf(['on', 'off']),
children: PropTypes.node,
domId: PropTypes.string.isRequired,
helperText: PropTypes.string,
hideLabel: PropTypes.bool,
icon: PropTypes.string,
iconOnClick: PropTypes.func,
iconPos: PropTypes.oneOf(['left', 'right']),
iconSR: PropTypes.string,
label: PropTypes.string,
maxLength: PropTypes.number,
required: PropTypes.bool,
storybookErrorPreview: PropTypes.bool,
type: PropTypes.string,
minRows: PropTypes.number,
maxRows: PropTypes.number,
onChange: PropTypes.func,
value: PropTypes.string,
};

export default TextFieldMultiline;
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
.textarea-wrapper {
padding: 1.15rem 0.75rem;
}

.input-field-textarea {
border: none;
width: 100%;
}

.input-field-textarea:focus {
outline: none;
}

.input-field-textarea::-webkit-scrollbar {
opacity: 1;
-webkit-appearance: none;
width: 7px;
height: 3px;
}
.input-field-textarea::-webkit-scrollbar-thumb {
opacity: 1;
border-radius: 99px;
background-color: rgba(156, 156, 156, 0.25);
box-shadow: 0 0 1px rgba(255, 255, 255, 0.25);
}

.input-field-text {
padding-top: $space-16;
position: relative;

&.icon-left {
.input-field {
padding-left: $space-48;
}

.icon {
left: $space-16;
}
}

&.icon-right {
.input-field {
padding-right: $space-48;
}

.icon {
transform: translate(calc(-100% - 12px), -50%);
}
}

&.hidden-label {
label {
@extend %screen-reader-text;
}
}

.icon {
position: absolute;
top: rem(42px);
transform: translate(0, -50%);
}
}

input::-ms-clear {
display: none;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import withFormik from "storybook-formik";
import { select, boolean } from "@storybook/addon-knobs";
import { withSmartKnobs } from "storybook-addon-smart-knobs";
import { TextFieldMultiline } from "./";
import iconArray from "../../Icon/helpers/getIconArray";

const TextFieldParameters = {
component: TextFieldMultiline,
componentSubtitle: "Utilize <TextFieldMultiline /> to present fields",
jest: ["TextFieldMultiline"]
};

storiesOf("components | Form Fields/Text Field - Multiline", module)
.addParameters(TextFieldParameters)
.addDecorator(
withSmartKnobs({
ignoreProps: [
"icon",
"touched",
"type",
"maxLength",
"children",
"storybookErrorPreview"
]
})
)
.addDecorator(withFormik)
.add("Default", () => (
<TextFieldMultiline
label="Label"
name="myInputName"
domId="myDomId"
helperText="Optional helper text"
hideLabel={boolean("hideLabel", false)}
icon={select("icon", iconArray, "placeholder-bold")}
storybookErrorPreview={boolean("error", false)}
required
/>
))
.add("With Min Rows", () => (
<TextFieldMultiline
label="Label"
name="myInputName"
domId="myDomId"
minRows="3"
helperText="Optional helper text"
hideLabel={boolean("hideLabel", false)}
icon={select("icon", iconArray, "placeholder-bold")}
storybookErrorPreview={boolean("error", false)}
required
/>
))
.add("With Max Rows", () => (
<TextFieldMultiline
label="Label"
name="myInputName"
domId="myDomId"
maxRows="5"
helperText="Optional helper text"
hideLabel={boolean("hideLabel", false)}
icon={select("icon", iconArray, "placeholder-bold")}
storybookErrorPreview={boolean("error", false)}
required
/>
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { Formik, Form } from 'formik';
import TextareaAutosize from 'react-textarea-autosize';
import { TextFieldMultiline } from './';
import { Label } from '../Label';
import { HelperText } from '../HelperText';

describe('<TextFieldMultiline />', () => {
it('Should render', () => {
const wrapper = mount(
<Formik initialValues={{ textField: '' }}>
<Form>
<TextFieldMultiline
label="label"
name="textField"
domId="textFieldId"
multiline="false"
helperText="Optional helper text"
/>
</Form>
</Formik>,
);
expect(wrapper.find(Label).length).toBe(1);
expect(wrapper.find(HelperText).length).toBe(1);
expect(wrapper.find(TextareaAutosize).length).toBe(1);
expect(toJson(wrapper)).toMatchSnapshot();
});
});
Loading

0 comments on commit 472a30d

Please sign in to comment.