From 54c768b953f77cf5704c955d6140582d5bc2a52d Mon Sep 17 00:00:00 2001 From: Artem Zakharchenko Date: Mon, 6 Apr 2020 09:02:48 +0200 Subject: [PATCH] Fixes broken typings with "React.forwardRef()" --- .../src/components/Composition.tsx | 12 ++--- .../atomic-layout/src/components/Only.tsx | 4 +- .../atomic-layout/src/components/Visible.tsx | 6 +-- .../atomic-layout/src/utils/forwardRef.ts | 7 +++ .../src/utils/withPlaceholder.tsx | 24 ++++----- .../test/createForwardRefTest.tsx | 49 +++++++++++++++---- 6 files changed, 69 insertions(+), 33 deletions(-) create mode 100644 packages/atomic-layout/src/utils/forwardRef.ts diff --git a/packages/atomic-layout/src/components/Composition.tsx b/packages/atomic-layout/src/components/Composition.tsx index d71535dd..2a205fcc 100644 --- a/packages/atomic-layout/src/components/Composition.tsx +++ b/packages/atomic-layout/src/components/Composition.tsx @@ -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` && { @@ -20,13 +21,12 @@ const CompositionWrapper = styled.div` } ` -const createAreaComponent = (areaName: string): AreaComponent => ( - props: BoxProps, -) => { - return -} +const createAreaComponent = (areaName: string): AreaComponent => + forwardRef((props: BoxProps, ref) => { + return + }) -const Composition = React.forwardRef( +const Composition = forwardRef( ({ children, ...restProps }, ref) => { const areasList = parseTemplates(restProps) diff --git a/packages/atomic-layout/src/components/Only.tsx b/packages/atomic-layout/src/components/Only.tsx index e447cd13..aea1f8cc 100644 --- a/packages/atomic-layout/src/components/Only.tsx +++ b/packages/atomic-layout/src/components/Only.tsx @@ -4,10 +4,11 @@ import Box from './Box' import useResponsiveQuery, { ResponsiveQueryParams, } from '../hooks/useResponsiveQuery' +import { forwardRef } from '../utils/forwardRef' export type OnlyProps = BoxProps & ResponsiveQueryParams -const Only = React.forwardRef( +const Only = forwardRef( ({ children, except, for: exactBreakpoint, from, to, ...restProps }, ref) => { const matches = useResponsiveQuery({ for: exactBreakpoint, @@ -15,6 +16,7 @@ const Only = React.forwardRef( to, except, }) + return ( matches && ( diff --git a/packages/atomic-layout/src/components/Visible.tsx b/packages/atomic-layout/src/components/Visible.tsx index a09a53e8..ee99d225 100644 --- a/packages/atomic-layout/src/components/Visible.tsx +++ b/packages/atomic-layout/src/components/Visible.tsx @@ -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 }) => @@ -12,10 +13,7 @@ const VisibleContainer = styled(Box)<{ matches: boolean }>` `} ` -/** - * Displays children when the given responsive query matches. - */ -const Visible = React.forwardRef( +const Visible = forwardRef( ( { children, except, for: exactBreakpointName, from, to, ...boxProps }, ref, diff --git a/packages/atomic-layout/src/utils/forwardRef.ts b/packages/atomic-layout/src/utils/forwardRef.ts new file mode 100644 index 00000000..a0aa24bc --- /dev/null +++ b/packages/atomic-layout/src/utils/forwardRef.ts @@ -0,0 +1,7 @@ +import * as React from 'react' + +export const forwardRef = ( + component: React.RefForwardingComponent, +): React.FC => { + return React.forwardRef(component) +} diff --git a/packages/atomic-layout/src/utils/withPlaceholder.tsx b/packages/atomic-layout/src/utils/withPlaceholder.tsx index aa9de3ef..a0cce889 100644 --- a/packages/atomic-layout/src/utils/withPlaceholder.tsx +++ b/packages/atomic-layout/src/utils/withPlaceholder.tsx @@ -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' /** @@ -11,19 +12,18 @@ export const withPlaceholder = ( Component: AreaComponent, breakpoints: Breakpoint[], ) => { - const Placeholder: React.FC = React.forwardRef< - unknown, - React.PropsWithChildren - >(({ children, ...restProps }, ref) => { - const matches = useMediaQuery(breakpoints) - return ( - matches && ( - - {children} - + const Placeholder = forwardRef( + ({ children, ...restProps }, ref) => { + const matches = useMediaQuery(breakpoints) + return ( + matches && ( + + {children} + + ) ) - ) - }) + }, + ) Placeholder.displayName = `Placeholder(${Component.displayName})` diff --git a/packages/atomic-layout/test/createForwardRefTest.tsx b/packages/atomic-layout/test/createForwardRefTest.tsx index 55a1b283..01d89814 100644 --- a/packages/atomic-layout/test/createForwardRefTest.tsx +++ b/packages/atomic-layout/test/createForwardRefTest.tsx @@ -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() expect(ref.current).toBeInstanceOf(HTMLDivElement) }) - it('Composition', () => { + it('Supports ref forwarding for the "Composition" component', () => { const ref = React.createRef() - render() + render( + +

Arbitrary content

+
, + ) 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( + + {(Areas) => ( + <> + Left + + Right + + + )} + , + ) + expect(leftRef.current).toBeInstanceOf(HTMLDivElement) + expect(rightRef.current).toBeInstanceOf(HTMLSpanElement) + }) + + it('Supports ref forwarding for the "Only" component', () => { const ref = React.createRef() render() expect(ref.current).toBeInstanceOf(HTMLDivElement) }) - it('Visible', () => { + it('Supports ref forwarding for the "Visible" component', () => { const ref = React.createRef() render() expect(ref.current).toBeInstanceOf(HTMLSpanElement)