Skip to content

Commit

Permalink
Fixes broken typings with "React.forwardRef()"
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed May 27, 2020
1 parent 2f27032 commit 54c768b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 33 deletions.
12 changes: 6 additions & 6 deletions packages/atomic-layout/src/components/Composition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@atomic-layout/core'
import Box from './Box'
import { withPlaceholder } from '../utils/withPlaceholder'
import { forwardRef } from '../utils/forwardRef'

const CompositionWrapper = styled.div<CompositionProps>`
&& {
Expand All @@ -20,13 +21,12 @@ const CompositionWrapper = styled.div<CompositionProps>`
}
`

const createAreaComponent = (areaName: string): AreaComponent => (
props: BoxProps,
) => {
return <Box area={areaName} {...props} />
}
const createAreaComponent = (areaName: string): AreaComponent =>
forwardRef((props: BoxProps, ref) => {
return <Box ref={ref} area={areaName} {...props} />
})

const Composition = React.forwardRef<unknown, CompositionProps>(
const Composition = forwardRef<unknown, CompositionProps>(
({ children, ...restProps }, ref) => {
const areasList = parseTemplates(restProps)

Expand Down
4 changes: 3 additions & 1 deletion packages/atomic-layout/src/components/Only.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import Box from './Box'
import useResponsiveQuery, {
ResponsiveQueryParams,
} from '../hooks/useResponsiveQuery'
import { forwardRef } from '../utils/forwardRef'

export type OnlyProps = BoxProps & ResponsiveQueryParams

const Only = React.forwardRef<unknown, OnlyProps>(
const Only = forwardRef<unknown, OnlyProps>(
({ children, except, for: exactBreakpoint, from, to, ...restProps }, ref) => {
const matches = useResponsiveQuery({
for: exactBreakpoint,
from,
to,
except,
})

return (
matches && (
<Box ref={ref} {...restProps}>
Expand Down
6 changes: 2 additions & 4 deletions packages/atomic-layout/src/components/Visible.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from 'styled-components'
import Box from './Box'
import { OnlyProps } from './Only'
import useResponsiveQuery from '../hooks/useResponsiveQuery'
import { forwardRef } from '../utils/forwardRef'

const VisibleContainer = styled(Box)<{ matches: boolean }>`
${({ matches }) =>
Expand All @@ -12,10 +13,7 @@ const VisibleContainer = styled(Box)<{ matches: boolean }>`
`}
`

/**
* Displays children when the given responsive query matches.
*/
const Visible = React.forwardRef<unknown, OnlyProps>(
const Visible = forwardRef<unknown, OnlyProps>(
(
{ children, except, for: exactBreakpointName, from, to, ...boxProps },
ref,
Expand Down
7 changes: 7 additions & 0 deletions packages/atomic-layout/src/utils/forwardRef.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react'

export const forwardRef = <RefType, Props>(
component: React.RefForwardingComponent<RefType, Props>,
): React.FC<Props & { ref?: RefType }> => {
return React.forwardRef<RefType, any>(component)
}
24 changes: 12 additions & 12 deletions packages/atomic-layout/src/utils/withPlaceholder.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react'
import { Breakpoint, AreaComponent, GenericProps } from '@atomic-layout/core'
import { forwardRef } from './forwardRef'
import { useMediaQuery } from '../hooks/useMediaQuery'

/**
Expand All @@ -11,19 +12,18 @@ export const withPlaceholder = (
Component: AreaComponent,
breakpoints: Breakpoint[],
) => {
const Placeholder: React.FC<GenericProps> = React.forwardRef<
unknown,
React.PropsWithChildren<GenericProps>
>(({ children, ...restProps }, ref) => {
const matches = useMediaQuery(breakpoints)
return (
matches && (
<Component ref={ref} {...restProps}>
{children}
</Component>
const Placeholder = forwardRef<unknown, GenericProps>(
({ children, ...restProps }, ref) => {
const matches = useMediaQuery(breakpoints)
return (
matches && (
<Component ref={ref} {...restProps}>
{children}
</Component>
)
)
)
})
},
)

Placeholder.displayName = `Placeholder(${Component.displayName})`

Expand Down
49 changes: 39 additions & 10 deletions packages/atomic-layout/test/createForwardRefTest.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,66 @@
import React from 'react'
import '../../atomic-layout-core/src/utils/breakpoints/withBreakpoints/matchMedia.mock'
import { render } from '@testing-library/react'
import '../../atomic-layout-core/src/utils/breakpoints/withBreakpoints/matchMedia.mock'
import {
Box as DefaultBox,
Composition as DefaultComposition,
Only as DefaultOnly,
Visible as DefaultVisible,
} from '../src/'

interface ComponentsMap {
Box: any
Composition: any
Only: any
Visible: any
Box: typeof DefaultBox
Composition: typeof DefaultComposition
Only: typeof DefaultOnly
Visible: typeof DefaultVisible
}

export const createForwardRefTest = (components: ComponentsMap) => {
const { Box, Composition, Only, Visible } = components

describe('Refs', () => {
it('Box', () => {
it('Supports ref forwarding for the "Box" component', () => {
const ref = React.createRef()
render(<Box ref={ref} />)
expect(ref.current).toBeInstanceOf(HTMLDivElement)
})

it('Composition', () => {
it('Supports ref forwarding for the "Composition" component', () => {
const ref = React.createRef()
render(<Composition ref={ref} as="span" />)
render(
<Composition ref={ref} as="span">
<p>Arbitrary content</p>
</Composition>,
)
expect(ref.current).toBeInstanceOf(HTMLSpanElement)
})

it('Only', () => {
it('Supports ref forwarding for the generated Area components', () => {
const leftRef = React.createRef()
const rightRef = React.createRef()
render(
<Composition areas="left right">
{(Areas) => (
<>
<Areas.Left ref={leftRef}>Left</Areas.Left>
<Areas.Right ref={rightRef} as="span">
Right
</Areas.Right>
</>
)}
</Composition>,
)
expect(leftRef.current).toBeInstanceOf(HTMLDivElement)
expect(rightRef.current).toBeInstanceOf(HTMLSpanElement)
})

it('Supports ref forwarding for the "Only" component', () => {
const ref = React.createRef()
render(<Only ref={ref} from="md" />)
expect(ref.current).toBeInstanceOf(HTMLDivElement)
})

it('Visible', () => {
it('Supports ref forwarding for the "Visible" component', () => {
const ref = React.createRef()
render(<Visible ref={ref} as="span" from="md" />)
expect(ref.current).toBeInstanceOf(HTMLSpanElement)
Expand Down

0 comments on commit 54c768b

Please sign in to comment.