Skip to content
This repository has been archived by the owner on May 7, 2021. It is now read-only.

Commit

Permalink
FormArrayControl component and Adapters for radios and checkboxes (#1312
Browse files Browse the repository at this point in the history
)

* working FormArrayControl component and Adapters for radio and checkboxes

* broken, but added a Field component to ease markup

* rebuilt the howdiditstart page using checkbox component.

* lint and passing tests. Not all new components have tests

* added a test for FormArrayControl

* cleaned up inputs, they also work properly now.

* tweaked input and text-area to accept attributes from react-final-form

* passing tests

* added condition to prevent rendering of node if conditional field doesn't exist

* some tweaks to ensure correct labelling of fields

* #1312-  Added the privacy consent checkbox fixes

* #1312-  Added whatWasAffected checkbox fixes

* cleanups

* Added the money lost checkbox fixes

* Added the missing UI container

* Added the information page checkbox fixes

* Added the conditional form for single field

* Merge conflicts

* Added missing dependencies

* Updated feedback forms

* Added the final forms fixes

* Remove unwanted copy -  Not included in the mocks

Co-authored-by: khalid elaggan <khalidelaggan@users.noreply.github.com>
  • Loading branch information
amazingphilippe and khalidelaggan committed Feb 18, 2020
1 parent c664f9a commit 35a9049
Show file tree
Hide file tree
Showing 18 changed files with 530 additions and 477 deletions.
24 changes: 24 additions & 0 deletions f2/src/components/Field/__tests__/Field.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'
import { ThemeProvider } from 'emotion-theming'
import canada from '../../../theme/canada'
import { render, cleanup } from '@testing-library/react'
import { Field } from '../'
import { Form } from 'react-final-form'

describe('<Field />', () => {
afterEach(cleanup)

it('renders', () => {
const submitMock = jest.fn()

render(
<ThemeProvider theme={canada}>
<Form
initialValues=""
onSubmit={submitMock}
render={() => <Field name="name" label="foo" helperText="help" />}
/>
</ThemeProvider>,
)
})
})
39 changes: 39 additions & 0 deletions f2/src/components/Field/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/** @jsx jsx */
import { jsx } from '@emotion/core'
import PropTypes from 'prop-types'
import { FormErrorMessage, FormControl } from '@chakra-ui/core'
import { FormHelperText } from '../FormHelperText'
import { FormLabel } from '../FormLabel'
import { Field as FieldAdapter } from 'react-final-form'
import { UniqueID } from '../unique-id'
import { Input } from '../input'

export const Field = ({ name, label, helperText, errorMessage, component }) => {
return (
<UniqueID>
{id => {
return (
<FormControl aria-labelledby={id}>
<FormLabel id={id} htmlFor={name}>
{label}
</FormLabel>
<FormHelperText>{helperText}</FormHelperText>
<FormErrorMessage>{errorMessage}</FormErrorMessage>
<FieldAdapter name={name} id={name} component={component} />
</FormControl>
)
}}
</UniqueID>
)
}
Field.defaultProps = {
component: Input,
}

Field.propTypes = {
children: PropTypes.any,
name: PropTypes.string,
label: PropTypes.any,
helperText: PropTypes.any,
errorMessage: PropTypes.any,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import { ThemeProvider } from 'emotion-theming'
import canada from '../../../theme/canada'
import { render, cleanup } from '@testing-library/react'
import { FormArrayControl } from '../'
import { Form } from 'react-final-form'

describe('<FormArrayControl />', () => {
afterEach(cleanup)

it('renders children', () => {
const submitMock = jest.fn()

const { getAllByText } = render(
<ThemeProvider theme={canada}>
<Form
initialValues=""
onSubmit={submitMock}
render={() => (
<FormArrayControl name="foo" label="bar" helperText="help">
<p>all</p>
</FormArrayControl>
)}
/>
</ThemeProvider>,
)

const label = getAllByText(/bar/)
const help = getAllByText(/help/)
const test = getAllByText(/all/)

expect(label).toHaveLength(1)
expect(help).toHaveLength(1)
expect(test).toHaveLength(1)
})
})
53 changes: 53 additions & 0 deletions f2/src/components/FormArrayControl/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/** @jsx jsx */
import PropTypes from 'prop-types'
import { jsx } from '@emotion/core'
import { FormErrorMessage, FormControl, Stack } from '@chakra-ui/core'
import { useField } from 'react-final-form'
import { FormLabel } from '../FormLabel'
import { FormHelperText } from '../FormHelperText'
import { UniqueID } from '../unique-id'

export const FormArrayControl = ({
label,
helperText,
errorMessage,
name,
children,
...rest
}) => {
const {
meta: { error, touched },
} = useField(name, { subscription: { touched: true, error: true } })
return (
<UniqueID>
{id => {
return (
<FormControl
as="fieldset"
aria-labelledby={id}
isInvalid={error && touched}
{...rest}
>
<FormLabel id={id} as="legend" htmlFor={name}>
{label}
</FormLabel>
<FormHelperText>{helperText}</FormHelperText>
<FormErrorMessage>{errorMessage}</FormErrorMessage>
{/** This component comes with a group attribute. We don't need to use Chakra's <CheckboxGroup> or <RadioGroup> as per the Chakra docs */}
<Stack shouldWrapChildren spacing={4}>
{children}
</Stack>
</FormControl>
)
}}
</UniqueID>
)
}

FormArrayControl.propTypes = {
label: PropTypes.any,
helperText: PropTypes.any,
errorMessage: PropTypes.any,
name: PropTypes.string,
children: PropTypes.any,
}
8 changes: 4 additions & 4 deletions f2/src/components/FormHelperText/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ export const FormHelperText = styled(ChakraFormHelperText)(
variant({
variants: {
above: {
mt: 0,
mb: 2,
mt: -2,
mb: 4,
},
below: {
mt: 2,
mt: 4,
mb: 0,
},
unstyled: {
Expand All @@ -22,7 +22,7 @@ export const FormHelperText = styled(ChakraFormHelperText)(

FormHelperText.defaultProps = {
variant: 'above',
as: 'div',
as: 'p',
fontSize: 'md',
color: 'black',
fontFamily: 'body',
Expand Down
2 changes: 1 addition & 1 deletion f2/src/components/FormLabel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ FormLabel.defaultProps = {
fontSize: 'xl',
fontWeight: 'bold',
fontFamily: 'body',
pb: 1,
mb: 2,
lineHeight: 1,
maxW: '600px',
}
51 changes: 44 additions & 7 deletions f2/src/components/checkbox/index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,55 @@
/** @jsx jsx */
import React from 'react'
import PropTypes from 'prop-types'
import { jsx } from '@emotion/core'
import { Text } from '../text'
import { UniqueID } from '../unique-id'
import { Box, VisuallyHidden, ControlBox, Icon, Flex } from '@chakra-ui/core'
import { VisuallyHidden, ControlBox, Icon, Flex } from '@chakra-ui/core'
import { useField } from 'react-final-form'
import { ConditionalForm } from '../container'

export const CheckboxAdapter = ({
name,
value,
defaultIsChecked,
children,
...props
}) => {
const {
input: { checked, ...input },
meta: { error, touched },
} = useField(name, {
type: 'checkbox', // important for RFF to manage the checked prop
value, // important for RFF to manage list of strings
defaultIsChecked,
})

return (
<Checkbox
input={input}
isChecked={checked}
isInvalid={error && touched}
conditionalField={props.conditionalField}
>
{children}
</Checkbox>
)
}

export const Checkbox = ({ input, label, isChecked, ...props }) => {
const isCheckedAndHasCondition = isChecked && props.conditionalField

export const Checkbox = ({ label, isChecked, ...props }) => {
return (
<UniqueID>
{id => {
return (
<Box as="label" {...props} id={id}>
<Flex align="center">
<React.Fragment>
<Flex as="label" id={id} align="center">
<VisuallyHidden
as="input"
type="checkbox"
defaultChecked={isChecked ? 'true' : ''}
{...input}
/>

<ControlBox
Expand Down Expand Up @@ -47,15 +81,18 @@ export const Checkbox = ({ label, isChecked, ...props }) => {
{props.children}
</Text>
</Flex>
</Box>

{isCheckedAndHasCondition && (
<ConditionalForm>{props.conditionalField}</ConditionalForm>
)}
</React.Fragment>
)
}}
</UniqueID>
)
}

Checkbox.defaultProps = {}

Checkbox.propTypes = {
conditionalField: PropTypes.any,
children: PropTypes.any,
}
25 changes: 15 additions & 10 deletions f2/src/components/container/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/** @jsx jsx **/
import React from 'react'
import PropTypes from 'prop-types'
import { jsx } from '@emotion/core'

Expand Down Expand Up @@ -33,16 +34,20 @@ export const LandingBox = props => (
)

export const ConditionalForm = ({ ...props }) => (
<Box
borderLeftWidth={1}
borderLeftColor="gray.400"
mt={1}
ml={5}
pl={6}
{...props}
>
{props.children}
</Box>
<React.Fragment>
{props.children && (
<Box
borderLeftWidth={1}
borderLeftColor="gray.400"
mt={1}
ml={5}
pl={6}
{...props}
>
{props.children}
</Box>
)}
</React.Fragment>
)

ConditionalForm.propTypes = {
Expand Down
6 changes: 1 addition & 5 deletions f2/src/components/input/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/** @jsx jsx **/
import { jsx } from '@emotion/core'
import PropTypes from 'prop-types'
import { Input as ChakraInput } from '@chakra-ui/core'

export const Input = props => (
Expand All @@ -22,10 +21,7 @@ export const Input = props => (
borderColor: 'black',
border: '3px',
}}
{...props.input}
{...props}
/>
)

Input.propTypes = {
children: PropTypes.any,
}
Loading

0 comments on commit 35a9049

Please sign in to comment.