Skip to content

Commit

Permalink
Create FormName render props component (#4038)
Browse files Browse the repository at this point in the history
* feat: create FormName render props component

* docs: document FormName

* Tweak FormName.md wording

* test(FormName): fix eslint issues
  • Loading branch information
jedwards1211 authored and erikras committed May 31, 2018
1 parent a57465a commit ca02205
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 0 deletions.
21 changes: 21 additions & 0 deletions docs/api/FormName.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# `FormName`

The `FormName` component allows you to get the name of the form in context - the name given to the enclosing `reduxForm` wrapper.
It is a [render props component](https://reactjs.org/docs/render-props.html).
This can be useful for building reusable components that show the status of any form in your app, for example.

## Importing

```javascript
var FormName = require('redux-form').FormName // ES5
```

```javascript
import { FormName } from 'redux-form' // ES6
```

## Props you can pass to `FormName`

### `children : (props: { form: string }) => React.Node` [required]

`FormName` will call this `children` function with the name of the enclosing form, and render whatever this function returns.
18 changes: 18 additions & 0 deletions src/FormName.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @flow

import * as React from 'react'
import PropTypes from 'prop-types'
import type {ReactContext} from './types'

export type Props = {
+children: (props: {form: string}) => React.Node,
}

const FormName = ({children}: Props, {_reduxForm}: ReactContext): React.Node => children({form: _reduxForm && _reduxForm.form})
FormName.contextTypes = {
_reduxForm: PropTypes.shape({
form: PropTypes.string.isRequired,
}).isRequired,
}

export default FormName
7 changes: 7 additions & 0 deletions src/FormNameProps.types.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @flow

import * as React from 'react'

export type Props = {
+children: (props: {form: string}) => React.Node,
}
69 changes: 69 additions & 0 deletions src/__tests__/FormName.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint react/no-multi-comp:0 */
import React, { Component } from 'react'
import { findDOMNode } from 'react-dom'
import { Provider } from 'react-redux'
import { combineReducers as plainCombineReducers, createStore } from 'redux'
import { combineReducers as immutableCombineReducers } from 'redux-immutablejs'
import TestUtils from 'react-dom/test-utils'
import createReduxForm from '../createReduxForm'
import createReducer from '../createReducer'
import FormName from '../FormName'
import plain from '../structure/plain'
import plainExpectations from '../structure/plain/__tests__/expectations'
import immutable from '../structure/immutable'
import immutableExpectations from '../structure/immutable/__tests__/expectations'

const describeFormName = (name, structure, combineReducers, setup) => {
const reduxForm = createReduxForm(structure)
const reducer = createReducer(structure)
const { fromJS } = structure
const makeStore = (initial = {}, logger) => {
const reducers = { form: reducer }
if (logger) {
reducers.logger = logger
}
return createStore(combineReducers(reducers), fromJS({ form: initial }))
}

describe(name, () => {
beforeAll(() => {
setup()
})

it('should pass name to child function and render what it returns', () => {
const store = makeStore({
testForm: {
values: {
foo: 42
}
}
})
class TestForm extends Component {
render() {
return (
<form>
<FormName>
{({form}) => <h1>Form name: {form}</h1>}
</FormName>
</form>
)
}
}
const DecoratedTestForm = reduxForm({ form: 'testForm' })(TestForm)
const comp = TestUtils.renderIntoDocument(
<Provider store={store}>
<DecoratedTestForm />
</Provider>
)

expect(findDOMNode(comp).outerHTML).toBe('<form><h1>Form name: testForm</h1></form>')
})
})
}

describeFormName('FormName.plain', plain, plainCombineReducers, () =>
expect.extend(plainExpectations)
)
describeFormName('FormName.immutable', immutable, immutableCombineReducers, () =>
expect.extend(immutableExpectations)
)
1 change: 1 addition & 0 deletions src/immutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as defaultShouldValidate } from './defaultShouldValidate'
export { default as defaultShouldError } from './defaultShouldError'
export { default as defaultShouldWarn } from './defaultShouldWarn'
export { default as Form } from './Form'
export { default as FormName } from './FormName'
export { default as FormSection } from './FormSection'
export { default as SubmissionError } from './SubmissionError'
// alias for propTypes
Expand Down
4 changes: 4 additions & 0 deletions src/immutable.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Params as DefaultShouldErrorParams } from './defaultShouldError'
import type { Params as DefaultShouldWarnParams } from './defaultShouldWarn'
import type { Config as ReduxFormConfig } from './createReduxForm'
import type { Props as _FormProps } from './Form'
import type { Props as _FormNameProps } from './FormName'
import type {
DefaultProps as FormSectionDefaultProps,
Props as _FormSectionProps
Expand Down Expand Up @@ -77,6 +78,7 @@ import type { Actions } from './actions.types'
type StructureMap = Object

export type FormProps = _FormProps
export type FormNameProps = _FormNameProps
export type FormSectionProps = _FormSectionProps
export type FieldProps = _FieldProps
export type FieldArrayProps = _FieldArrayProps
Expand Down Expand Up @@ -115,6 +117,8 @@ declare export var fieldArrayPropTypes: Object

declare export var formPropTypes: Object

declare export var FormName: React.ComponentType<FormNameProps>

declare export var Field: React.ComponentType<FieldInputProps>

declare export var Fields: React.ComponentType<FieldsInputProps>
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as defaultShouldValidate } from './defaultShouldValidate'
export { default as defaultShouldError } from './defaultShouldError'
export { default as defaultShouldWarn } from './defaultShouldWarn'
export { default as Form } from './Form'
export { default as FormName } from './FormName'
export { default as FormSection } from './FormSection'
export { default as SubmissionError } from './SubmissionError'
// alias for propTypes
Expand Down
4 changes: 4 additions & 0 deletions src/index.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Params as DefaultShouldErrorParams } from './defaultShouldError'
import type { Params as DefaultShouldWarnParams } from './defaultShouldWarn'
import type { Config as ReduxFormConfig } from './createReduxForm'
import type { Props as _FormProps } from './Form'
import type { Props as _FormNameProps } from './FormName'
import type {
DefaultProps as FormSectionDefaultProps,
Props as FormSectionProps
Expand Down Expand Up @@ -77,6 +78,7 @@ import type {
type StructureMap = Object

export type FormProps = _FormProps
export type FormNameProps = _FormNameProps
export type FieldProps = _FieldProps
export type FieldArrayProps = _FieldArrayProps

Expand Down Expand Up @@ -114,6 +116,8 @@ declare export var fieldArrayPropTypes: Object

declare export var formPropTypes: Object

declare export var FormName: React.ComponentType<FormNameProps>

declare export var Field: React.ComponentType<FieldInputProps>

declare export var Fields: React.ComponentType<FieldsInputProps>
Expand Down
6 changes: 6 additions & 0 deletions src/util/FormNameProps.types.js.flow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @flow
import * as React from 'react'

export type Props = {
children: (form: {name: string}) => React.Node,
}

0 comments on commit ca02205

Please sign in to comment.