Skip to content

Commit

Permalink
fix: add custom react node inputs (#8)
Browse files Browse the repository at this point in the history
fix: add custom react node inputs
  • Loading branch information
jlison authored Aug 20, 2019
2 parents 068c15e + 75b76c7 commit 52bcde8
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 12 deletions.
40 changes: 30 additions & 10 deletions src/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import useForm from 'react-hook-form';
import {useTranslation} from 'react-i18next';
import {Col, Form, Row} from 'reactstrap';

import {FormConfig, FormHeader} from './interfaces/FormConfig';
import {FormConfig, FormHeader, FormHooks} from './interfaces/FormConfig';
import fetch from './utils/fetch';
import InputForm from './components/Input';
import SelectForm from './components/SingleSelect';
Expand All @@ -16,6 +16,7 @@ interface Props {
[key: string]: any;
};
csrfUrl?: string;
getForm?: (formHooks: FormHooks) => any;
onSubmit: <T>(...args: any) => Promise<T | void> | T | void;
}

Expand All @@ -27,7 +28,7 @@ const dependencies = [
];

/** Form generator */
export default ({csrfUrl, defaultValues, form, onSubmit}: Props) => {
export default ({csrfUrl, defaultValues, form, getForm, onSubmit}: Props) => {
const formHooks = useForm({defaultValues});
const [csrf, setCsrf] = useState();
const {t} = useTranslation();
Expand Down Expand Up @@ -83,8 +84,8 @@ export default ({csrfUrl, defaultValues, form, onSubmit}: Props) => {
<Row key={`br-${elementConfig.name}-${elementConfig.type}`}>
{elementConfig.inputs.map((input, i) => {
if (
!mapper.hasOwnProperty(input.type) ||
typeof (mapper as any)[input.type] !== 'function'
!mapper.hasOwnProperty(input.type as string) ||
typeof (mapper as any)[input.type as string] !== 'function'
) {
return null;
}
Expand All @@ -93,7 +94,7 @@ export default ({csrfUrl, defaultValues, form, onSubmit}: Props) => {
<Col
key={`bc-${name}-${input.type}-${i}`}
md={input.col || 12 / elementConfig.inputs.length}>
{(mapper as any)[input.type](input)}
{(mapper as any)[input.type as string](input)}
</Col>
);
})}
Expand All @@ -106,18 +107,31 @@ export default ({csrfUrl, defaultValues, form, onSubmit}: Props) => {
*/
const renderInput = (elementConfig: FormConfig): React.ReactNode => (
<Row key={`br-${elementConfig.name}-${elementConfig.type}`}>
<Col md={12}>{(mapper as any)[elementConfig.type](elementConfig)}</Col>
<Col md={12}>
{(mapper as any)[elementConfig.type as string](elementConfig)}
</Col>
</Row>
);

/**
* Render custom node as a form input.
* @param elementConfig Component/element form configuration object.
*/
const renderCustomNode = (elementConfig: FormConfig): React.ReactNode => (
<React.Fragment key={elementConfig.name}>
{elementConfig.type}
</React.Fragment>
);

/**
* Render form element based on passed form config.
* @param elementConfig Form configuration object to render form element.
*/
const renderElement = (elementConfig: FormConfig) => {
if (
!mapper.hasOwnProperty(elementConfig.type) ||
typeof (mapper as any)[elementConfig.type] !== 'function'
typeof elementConfig.type === 'string' &&
(!mapper.hasOwnProperty(elementConfig.type) ||
typeof (mapper as any)[elementConfig.type] !== 'function')
) {
return null;
}
Expand All @@ -128,10 +142,12 @@ export default ({csrfUrl, defaultValues, form, onSubmit}: Props) => {
nodes.push(renderHeader(elementConfig.header));
}

if (elementConfig.inputs) {
if (typeof elementConfig.type === 'string' && !elementConfig.inputs) {
nodes.push(renderInput(elementConfig));
} else if (elementConfig.inputs) {
nodes.push(renderMultipleInputs(elementConfig));
} else {
nodes.push(renderInput(elementConfig));
nodes.push(renderCustomNode(elementConfig));
}

return (
Expand All @@ -153,6 +169,10 @@ export default ({csrfUrl, defaultValues, form, onSubmit}: Props) => {
return onSubmit(data);
};

if (typeof getForm === 'function') {
getForm({...formHooks, csrf});
}

return (
<Form onSubmit={formHooks.handleSubmit(submitWrapper)}>
{form.map((elementConfig) => renderElement(elementConfig))}
Expand Down
5 changes: 4 additions & 1 deletion src/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export default ({
<InputGroup>
{addon && (
<InputGroupAddon addonType={addon.type as 'prepend' | 'append'}>
<InputGroupText>{addon.icon && <>{addon.icon}</>}</InputGroupText>
<InputGroupText>
{addon.icon && <>{addon.icon}</>}{' '}
{addon.text && <>{addon.text}</>}
</InputGroupText>
</InputGroupAddon>
)}
<Input
Expand Down
6 changes: 5 additions & 1 deletion src/interfaces/FormConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface FormHeader {

export interface FormConfig {
name: string;
type: string;
type: string | React.ReactNode;
col?: number;
inputType?: InputType | string;
addon?: {
Expand Down Expand Up @@ -44,3 +44,7 @@ export interface DefaultInputProps
elementConfig: FormConfig;
formState: FormProps['formState'] | unknown[] | unknown;
}

export interface FormHooks extends Omit<DefaultInputProps, 'elementConfig'> {
csrf: string;
}

0 comments on commit 52bcde8

Please sign in to comment.