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

FormArrayControl component and Adapters for radios and checkboxes #1312

Merged
merged 31 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8ec2817
working FormArrayControl component and Adapters for radio and checkboxes
amazingphilippe Feb 6, 2020
43b350c
broken, but added a Field component to ease markup
amazingphilippe Feb 10, 2020
224e8dd
Merge branch 'master' of github.com:cds-snc/report-a-cybercrime into …
amazingphilippe Feb 10, 2020
0554387
rebuilt the howdiditstart page using checkbox component.
amazingphilippe Feb 10, 2020
984bb3f
lint and passing tests. Not all new components have tests
amazingphilippe Feb 11, 2020
aa7c496
added a test for FormArrayControl
amazingphilippe Feb 11, 2020
082a5fc
merged with master
amazingphilippe Feb 11, 2020
9747eba
cleaned up inputs, they also work properly now.
amazingphilippe Feb 12, 2020
c027e39
tweaked input and text-area to accept attributes from react-final-form
amazingphilippe Feb 12, 2020
555f53e
passing tests
amazingphilippe Feb 12, 2020
0c3aca6
added condition to prevent rendering of node if conditional field doe…
amazingphilippe Feb 12, 2020
572b87b
some tweaks to ensure correct labelling of fields
amazingphilippe Feb 13, 2020
5bcaa44
#1312- Added the privacy consent checkbox fixes
khalidelaggan Feb 18, 2020
ca03257
#1312- Added whatWasAffected checkbox fixes
khalidelaggan Feb 18, 2020
7c2fdd5
cleanups
khalidelaggan Feb 18, 2020
e031580
Added the money lost checkbox fixes
khalidelaggan Feb 18, 2020
5e9cada
Added the missing UI container
khalidelaggan Feb 18, 2020
7d857e8
Added the information page checkbox fixes
khalidelaggan Feb 18, 2020
162fbe8
Added the conditional form for single field
khalidelaggan Feb 18, 2020
d124ba8
Merge branch 'master' into checkbox-component
khalidelaggan Feb 18, 2020
edede7e
Merge branch 'master' into checkbox-component
khalidelaggan Feb 18, 2020
21bd04b
Merge conflicts
khalidelaggan Feb 18, 2020
f9bbb27
Merge branch 'checkbox-component' of github.com:cds-snc/report-a-cybe…
khalidelaggan Feb 18, 2020
5d5d02a
Added missing dependencies
khalidelaggan Feb 18, 2020
fe34926
Merge branch 'master' into checkbox-component
khalidelaggan Feb 18, 2020
3e7af8e
Updated feedback forms
khalidelaggan Feb 18, 2020
0ed51a7
Merge remote-tracking branch 'origin/master' into checkbox-component
khalidelaggan Feb 18, 2020
a8fb04a
Added the final forms fixes
khalidelaggan Feb 18, 2020
d822876
Merge branch 'master' into checkbox-component
khalidelaggan Feb 18, 2020
6e21f71
Remove unwanted copy - Not included in the mocks
khalidelaggan Feb 18, 2020
d31a275
Merge branch 'checkbox-component' of github.com:cds-snc/report-a-cybe…
khalidelaggan Feb 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 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,
}
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.object,
helperText: PropTypes.object,
errorMessage: PropTypes.object,
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',
}
49 changes: 42 additions & 7 deletions f2/src/components/checkbox/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
/** @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,
})

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

export const Checkbox = ({ input, label, isChecked, ...props }) => {
return (
<UniqueID>
{id => {
return (
<Box as="label" {...props} id={id}>
<Flex align="center">
<React.Fragment>
<Flex as="label" {...props} id={id} align="center">
<VisuallyHidden
{...input}
as="input"
type="checkbox"
defaultChecked={isChecked ? 'true' : ''}
Expand Down Expand Up @@ -47,15 +79,18 @@ export const Checkbox = ({ label, isChecked, ...props }) => {
{props.children}
</Text>
</Flex>
</Box>

{isChecked && (
<ConditionalForm>{props.conditionalField}</ConditionalForm>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want props.conditionalField in the &&, otherwise if there’s no conditional it’ll still make an empty <ConditionalForm/>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I had this issue. Good call

)}
</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 All @@ -18,16 +19,20 @@ export const InfoCard = 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
41 changes: 33 additions & 8 deletions f2/src/components/radio/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
/** @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, Flex } from '@chakra-ui/core'
import { useField } from 'react-final-form'
import { ConditionalForm } from '../container'

export const Radio = ({ label, isChecked, ...props }) => {
export const RadioAdapter = ({ name, value, defaultIsChecked, children }) => {
const {
input: { checked, ...input },
meta: { error, touched },
} = useField(name, {
type: 'radio',
value,
defaultIsChecked,
})

return (
<Radio input={input} isChecked={checked} isInvalid={error && touched}>
{children}
</Radio>
)
}

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

Expand Down Expand Up @@ -51,15 +76,15 @@ export const Radio = ({ label, isChecked, ...props }) => {
{props.children}
</Text>
</Flex>
</Box>
{isChecked && <ConditionalForm>{conditionalField}</ConditionalForm>}
</React.Fragment>
)
}}
</UniqueID>
)
}

Radio.defaultProps = {}

Radio.propTypes = {
children: PropTypes.any,
conditionalField: PropTypes.object,
}
Loading