Skip to content

Commit

Permalink
chore: improve typing
Browse files Browse the repository at this point in the history
  • Loading branch information
pedronauck committed Apr 1, 2018
1 parent c36960e commit 129a44f
Showing 1 changed file with 34 additions and 29 deletions.
63 changes: 34 additions & 29 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
import * as React from 'react'
import { ComponentType, ReactNode, ReactElement } from 'react'
import { ReactNode, ReactElement } from 'react'

const { values, keys, assign } = Object

export type ChildrenFn<P = any> = (props: P) => ReactNode
export type ChildrenFn<P> = (props: P) => ReactNode

export type MapperValue =
| ReactElement<any>
| ChildrenFn<{
renderProp?: ChildrenFn
[key: string]: any
}>

export type Mapper<R> = Record<keyof R, MapperValue>

export type RPC<RenderProps, Props = {}> = ComponentType<
Props & {
children: ChildrenFn<RenderProps>
}
>

function omit<R = object>(obj: any, omitProps: string[]): R {
function omit<R = object>(omitProps: string[], obj: any): R {
const newObj = keys(obj)
.filter((key: string): boolean => omitProps.indexOf(key) === -1)
.reduce(
Expand All @@ -31,37 +16,57 @@ function omit<R = object>(obj: any, omitProps: string[]): R {
return newObj as R
}

function prop<T = any>(key: string, obj: any): T {
return obj[key]
}

const isFn = (val: any): boolean => Boolean(val) && typeof val === 'function'

const isValidRenderProp = (prop: ReactNode | ChildrenFn<any>): boolean =>
React.isValidElement(prop) || isFn(prop)

export function adopt<RP extends Record<string, any>, P = {}>(
mapper: Mapper<RP>
): RPC<RP, P> {
export type RPC<RP, P = {}> = React.SFC<
P & {
children: ChildrenFn<RP>
}
>

export type MapperComponent<RP, P = {}> = React.SFC<
P & {
render?: ChildrenFn<RP & P>
}
>

export type MapperValue<RP, P> = ReactElement<any> | MapperComponent<RP, P>

export type Mapper<RP, P> = Record<keyof RP, MapperValue<RP, P>>

export function adopt<RP, P = {}>(mapper: Mapper<RP, P>): RPC<RP, P> {
if (!values(mapper).some(isValidRenderProp)) {
throw new Error(
'The render props object mapper just accept valid elements as value'
)
}

const Children: RPC<RP, P> = ({ children, ...rest }: any) =>
const Children: any = ({ children, ...rest }: any) =>
isFn(children) && children(rest)

const reducer = (Component: RPC<RP, P>, key: keyof RP): RPC<RP, P> => ({
const reducer = (Component: RPC<RP>, key: string): RPC<RP> => ({
children,
...rest
}: {
children: ChildrenFn<RP>
}) => (
<Component {...rest}>
{props => {
const element: any = mapper[key]
const propsWithoutRest = omit<RP>(props, keys(rest))
const element = prop(key, mapper)
const propsWithoutRest = omit<RP>(keys(rest), props)

const render = (cProps: Partial<RP>) =>
const render: ChildrenFn<RP> = cProps =>
isFn(children) &&
children(assign({}, propsWithoutRest, { [key]: cProps }))
children(
assign({}, propsWithoutRest, {
[key]: cProps,
})
)

return isFn(element)
? React.createElement(element, assign({}, rest, props, { render }))
Expand Down

0 comments on commit 129a44f

Please sign in to comment.