Skip to content

Instantly share code, notes, and snippets.

@tomodutch
Created June 10, 2018 17:19
Show Gist options
  • Select an option

  • Save tomodutch/991bee8d5e58bafc438e3fb0abad9f60 to your computer and use it in GitHub Desktop.

Select an option

Save tomodutch/991bee8d5e58bafc438e3fb0abad9f60 to your computer and use it in GitHub Desktop.
2018-06-10 or how they fucked up the type definitions
import * as React from 'react';
import {
Field,
FieldArray,
FieldIterate,
FieldsProps,
GenericFieldArray,
WrappedFieldArrayProps,
WrappedFieldInputProps,
WrappedFieldProps
} from "redux-form";
type FieldArrayProps<FieldValue> = WrappedFieldArrayProps<FieldValue>
& { label: string, empty: FieldValue }
function push<Data>(empty: Data, fields: FieldsProps<Data>) {
return () => {
fields.push(empty)
}
}
export function createRepeatedRender<Data>(renderer: FieldIterate<Data, JSX.Element>) {
return (props: FieldArrayProps<Data>) => {
const {fields, meta: {error, submitFailed}, label, empty} = props;
const hasError = error && submitFailed;
return <div className={hasError ? 'error' : ''}>
<button type="button" onClick={push(empty, fields)}>{label}</button>
{hasError && <span>{error}</span>}
{fields.map(renderer)}
</div>
}
}
interface InputProps {
type?: string
}
type Renderer = (input: WrappedFieldInputProps, label?: string, rest?: any) => JSX.Element
type FieldProps = WrappedFieldProps & { required?: boolean }
function createRenderer<T>(renderer: Renderer) {
return (props: FieldProps & T) => {
const {input, meta, label, required} = props;
const changed = (meta as any).changed;
const hasError = meta.error && (changed || meta.submitFailed);
const requiredText = required ? <b style={{color: 'red'}}> *</b> : "";
return <div className={[
hasError ? 'error' : '',
meta.active ? 'active' : '',
'input-element',
].join(' ')}>
<label>{label}{requiredText}</label>
{renderer(input, label, props)}
{hasError && <span>{meta.error}</span>}
</div>
}
}
export const RenderInput = createRenderer<InputProps>((input, label, {type}: InputProps) =>
<input {...input}
type={type || "text"}
placeholder={label}/>);
export const RepeatableMember = createRepeatedRender<{}>((name, index, fields) => {
return <div key={index}>
<button
type="button"
title="Remove Member">Remove Member #{index + 1}</button>
<h4>Member #{index + 1}</h4>
<Field name={`${name}.firstName`}
label="First Name"
component={RenderInput}/>
</div>
});
export const RepeatableField = FieldArray as new <Data>() => GenericFieldArray<Data, { label: string, empty: Data }>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment