Skip to content

Commit

Permalink
feat #139 - Add focused prop to FormInput and allow refs to be passed…
Browse files Browse the repository at this point in the history
… to input (#140)

Closes #139

Co-authored-by: github-actions <[email protected]>
  • Loading branch information
nancy-dassana and github-actions authored Nov 9, 2020
1 parent 85d3293 commit aac8ecb
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 6 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dassana-io/web-components",
"version": "0.6.5",
"version": "0.6.6",
"publishConfig": {
"registry": "https://npm.pkg.github.com/dassana-io"
},
Expand Down
29 changes: 28 additions & 1 deletion src/components/Form/FormInput/FormInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@ import React from 'react'
import FormInput, { FormInputProps } from './index'
import { mount, ReactWrapper } from 'enzyme'

const mockFocus = jest.fn()

jest.mock('react', () => ({
...(jest.requireActual('react') as {}),
useRef: () => ({
current: {
focus: mockFocus
}
})
}))

jest.mock('react-hook-form', () => ({
...jest.requireActual('react-hook-form'),
...(jest.requireActual('react-hook-form') as {}),
Controller: () => <div />,
useFormContext: () => ({
control: jest.fn(),
Expand Down Expand Up @@ -90,4 +101,20 @@ describe('FormInput', () => {
required: true
})
})

it('focuses on the input if required', () => {
wrapper = mount(
<FieldContext.Provider
value={{
initialValues: {},
loading: true,
onSubmit: mockOnSubmit
}}
>
<FormInput focused name='foo' required />
</FieldContext.Provider>
)

expect(mockFocus).toHaveBeenCalled()
})
})
16 changes: 14 additions & 2 deletions src/components/Form/FormInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
import { Input as AntDInput } from 'antd'
import { BaseFieldProps } from '../types'
import FieldLabel from '../FieldLabel'
import { getFormFieldDataTag } from '../utils'
import { Controller, useFormContext } from 'react-hook-form'
import FieldContext, { FieldContextProps } from '../FieldContext'
import { Input, InputProps } from 'components/Input'
import React, { FC, useContext } from 'react'
import React, { FC, useContext, useEffect, useRef } from 'react'

export interface FormInputProps
extends BaseFieldProps,
Omit<InputProps, 'onChange' | 'value'> {}
Omit<InputProps, 'onChange' | 'value'> {
focused?: boolean
}

const FormInput: FC<FormInputProps> = ({
fullWidth = false,
label,
labelSkeletonWidth,
focused,
name,
required,
rules = {},
...rest
}: FormInputProps) => {
const inputRef = useRef<AntDInput>(null)
const { control, errors } = useFormContext()
const { initialValues, loading } = useContext<FieldContextProps>(
FieldContext
)

useEffect(() => {
if (focused && inputRef.current) {
inputRef.current.focus()
}
}, [focused])

if (required) {
rules.required = true
}
Expand All @@ -50,6 +61,7 @@ const FormInput: FC<FormInputProps> = ({
dataTag={getFormFieldDataTag(name)}
error={errors[name]}
fullWidth={fullWidth}
inputRef={inputRef}
loading={loading}
onChange={onChange}
value={value}
Expand Down
17 changes: 16 additions & 1 deletion src/components/Input/Input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { act } from 'react-dom/test-utils'
import { Input as AntDInput } from 'antd'
import { Input } from './index'
import React from 'react'
import { Skeleton } from '../Skeleton'
import { mount, ReactWrapper, shallow } from 'enzyme'
import React, { createRef } from 'react'

let wrapper: ReactWrapper

Expand Down Expand Up @@ -35,6 +36,20 @@ describe('Input', () => {
expect(wrapper.find(AntDInput).props().disabled).toBeTruthy()
})

it('correctly passes the ref if one is provided', () => {
const inputRef = createRef<AntDInput>()

wrapper = mount(<Input inputRef={inputRef} />)

expect(document.activeElement?.tagName).toMatch('BODY')

act(() => {
inputRef.current?.focus()
})

expect(document.activeElement?.tagName).toMatch('INPUT')
})

it('correctly passes the placeholder prop', () => {
wrapper = mount(<Input placeholder='Testing' />)

Expand Down
5 changes: 4 additions & 1 deletion src/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
fieldErrorStyles
} from '../assets/styles/styleguide'
import { generateInputSkeletonStyles, generateInputStyles } from './utils'
import React, { FC } from 'react'
import React, { FC, RefObject } from 'react'

const { dark, light } = ThemeType

Expand Down Expand Up @@ -45,6 +45,7 @@ const InputSkeleton: FC<InputProps> = (props: InputProps) => {
}

export interface InputProps extends BaseFormElementProps {
inputRef?: RefObject<AntDInput>
/**
* Type of input (ex: text, password)
* @default text
Expand All @@ -57,6 +58,7 @@ export const Input: FC<InputProps> = (props: InputProps) => {
classes = [],
dataTag,
disabled = false,
inputRef,
onChange,
error = false,
loading = false,
Expand Down Expand Up @@ -94,6 +96,7 @@ export const Input: FC<InputProps> = (props: InputProps) => {
className={cn(componentClasses.container, inputClasses)}
disabled={disabled}
placeholder={placeholder}
ref={inputRef}
type={type}
{...controlledCmpProps}
{...getDataTestAttributeProp('input', dataTag)}
Expand Down

0 comments on commit aac8ecb

Please sign in to comment.