From de739554c8b4d55d8d805c24f268be5235ac1269 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 17 Jul 2018 15:23:16 -0300 Subject: [PATCH] Forward Ref Stub --- .../test/__snapshots__/loadMore.spec.tsx.snap | 9 +++++ .../__snapshots__/renderReplies.spec.tsx.snap | 3 ++ .../__snapshots__/renderStream.spec.tsx.snap | 3 ++ .../showAllReplies.spec.tsx.snap | 9 +++++ .../ui/components/BaseButton/BaseButton.tsx | 23 ++++++++---- .../client/ui/components/Button/Button.tsx | 14 ++++++-- src/core/client/ui/components/Flex/Flex.tsx | 14 ++++++-- .../components/RelativeTime/RelativeTime.tsx | 12 +++++-- .../ui/components/Typography/Typography.tsx | 15 +++++--- src/core/client/ui/hocs/index.ts | 1 + src/core/client/ui/hocs/withForwardRef.tsx | 36 +++++++++++++++++++ src/core/client/ui/hocs/withKeyboardFocus.tsx | 10 ++++-- src/core/client/ui/hocs/withMouseHover.tsx | 10 ++++-- 13 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 src/core/client/ui/hocs/withForwardRef.tsx diff --git a/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap index b3d193c41..56a90c377 100644 --- a/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap @@ -33,6 +33,9 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Post @@ -169,6 +172,9 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Post @@ -247,6 +253,9 @@ exports[`renders comment stream 1`] = ` onClick={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Load More diff --git a/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap index 24fe4fe1d..56758219a 100644 --- a/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap @@ -33,6 +33,9 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Post diff --git a/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap index 3a3599547..433957511 100644 --- a/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap @@ -33,6 +33,9 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Post diff --git a/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap index 2762b7dae..a8570269a 100644 --- a/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap @@ -33,6 +33,9 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Post @@ -114,6 +117,9 @@ exports[`renders comment stream 1`] = ` onClick={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Show All Replies @@ -158,6 +164,9 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onFocus={[Function]} onMouseDown={[Function]} + onMouseOut={[Function]} + onMouseOver={[Function]} + onTouchEnd={[Function]} > Post diff --git a/src/core/client/ui/components/BaseButton/BaseButton.tsx b/src/core/client/ui/components/BaseButton/BaseButton.tsx index eb12d9826..45c2c7985 100644 --- a/src/core/client/ui/components/BaseButton/BaseButton.tsx +++ b/src/core/client/ui/components/BaseButton/BaseButton.tsx @@ -1,8 +1,13 @@ import cn from "classnames"; -import React from "react"; +import React, { Ref } from "react"; import { ButtonHTMLAttributes, StatelessComponent } from "react"; -import { withKeyboardFocus, withMouseHover, withStyles } from "talk-ui/hocs"; +import { + withForwardRef, + withKeyboardFocus, + withMouseHover, + withStyles, +} from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; import * as styles from "./BaseButton.css"; @@ -10,7 +15,6 @@ import * as styles from "./BaseButton.css"; interface InnerProps extends ButtonHTMLAttributes { /** If set renders an anchor tag instead */ anchor?: boolean; - /** * This prop can be used to add custom classnames. * It is handled by the `withStyles `HOC. @@ -22,6 +26,12 @@ interface InnerProps extends ButtonHTMLAttributes { /** This is passed by the `withMouseHover` HOC */ mouseHover?: boolean; + + /** ref to the HTMLButtonElement */ + ref?: Ref; + + /** Internal: Forwarded Ref */ + forwardRef?: Ref; } /** @@ -34,6 +44,7 @@ const BaseButton: StatelessComponent = ({ classes, keyboardFocus, mouseHover, + forwardRef, type: typeProp, ...rest }) => { @@ -58,11 +69,11 @@ const BaseButton: StatelessComponent = ({ [classes.mouseHover]: mouseHover, }); - return ; + return ; }; -const enhanced = withStyles(styles)( - withMouseHover(withKeyboardFocus(BaseButton)) +const enhanced = withForwardRef( + withStyles(styles)(withMouseHover(withKeyboardFocus(BaseButton))) ); export type BaseButtonProps = PropTypesOf; export default enhanced; diff --git a/src/core/client/ui/components/Button/Button.tsx b/src/core/client/ui/components/Button/Button.tsx index 0de34a31e..8a73c0c1a 100644 --- a/src/core/client/ui/components/Button/Button.tsx +++ b/src/core/client/ui/components/Button/Button.tsx @@ -1,8 +1,8 @@ import cn from "classnames"; import { pick } from "lodash"; -import React, { ButtonHTMLAttributes } from "react"; +import React, { ButtonHTMLAttributes, Ref } from "react"; -import { withStyles } from "talk-ui/hocs"; +import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; import BaseButton, { BaseButtonProps } from "../BaseButton"; @@ -28,6 +28,12 @@ interface InnerProps extends ButtonHTMLAttributes { /** If set renders a button with secondary colors */ secondary?: boolean; + + /** ref to the HTMLButtonElement */ + ref?: Ref; + + /** Internal: Forwarded Ref */ + forwardRef?: Ref; } class Button extends React.Component { @@ -40,6 +46,7 @@ class Button extends React.Component { primary, secondary, disabled, + forwardRef, ...rest } = this.props; @@ -57,12 +64,13 @@ class Button extends React.Component { className={rootClassName} classes={pick(classes, "keyboardFocus", "mouseHover")} disabled={disabled} + ref={forwardRef} {...rest} /> ); } } -const enhanced = withStyles(styles)(Button); +const enhanced = withForwardRef(withStyles(styles)(Button)); export type ButtonProps = PropTypesOf; export default enhanced; diff --git a/src/core/client/ui/components/Flex/Flex.tsx b/src/core/client/ui/components/Flex/Flex.tsx index 8ffd9c231..8bf770ec7 100644 --- a/src/core/client/ui/components/Flex/Flex.tsx +++ b/src/core/client/ui/components/Flex/Flex.tsx @@ -1,8 +1,9 @@ import cn from "classnames"; -import React from "react"; +import React, { Ref } from "react"; import { StatelessComponent } from "react"; import { pascalCase } from "talk-common/utils"; +import { withForwardRef } from "talk-ui/hocs"; import * as styles from "./Flex.css"; @@ -21,6 +22,12 @@ interface InnerProps { itemGutter?: boolean | "half"; className?: string; wrap?: boolean | "reverse"; + + /** Ref to the root element */ + ref?: Ref; + + /** Internal: Forwarded Ref */ + forwardRef?: Ref; } const Flex: StatelessComponent = props => { @@ -31,6 +38,7 @@ const Flex: StatelessComponent = props => { direction, itemGutter, wrap, + forwardRef, ...rest } = props; @@ -55,7 +63,7 @@ const Flex: StatelessComponent = props => { const classNames: string = cn(styles.root, className, classObject); - return
; + return
; }; -export default Flex; +export default withForwardRef(Flex); diff --git a/src/core/client/ui/components/RelativeTime/RelativeTime.tsx b/src/core/client/ui/components/RelativeTime/RelativeTime.tsx index 3a8022656..2f8d56715 100644 --- a/src/core/client/ui/components/RelativeTime/RelativeTime.tsx +++ b/src/core/client/ui/components/RelativeTime/RelativeTime.tsx @@ -1,9 +1,9 @@ import cn from "classnames"; -import React from "react"; +import React, { Ref } from "react"; import TimeAgo, { Formatter } from "react-timeago"; import { UIContext } from "talk-ui/components"; -import { withStyles } from "talk-ui/hocs"; +import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; import * as styles from "./RelativeTime.css"; @@ -14,6 +14,12 @@ interface InnerProps { classes: typeof styles; className?: string; formatter?: Formatter; + + /** Ref to the root element */ + ref?: Ref; + + /** Internal: Forwarded Ref */ + forwardRef?: Ref; } const defaultFormatter: Formatter = (value, unit, suffix, timestamp: string) => @@ -37,6 +43,6 @@ class RelativeTime extends React.Component { } } -const enhanced = withStyles(styles)(RelativeTime); +const enhanced = withForwardRef(withStyles(styles)(RelativeTime)); export type RelativeTimeProps = PropTypesOf; export default enhanced; diff --git a/src/core/client/ui/components/Typography/Typography.tsx b/src/core/client/ui/components/Typography/Typography.tsx index b743305e6..b78347944 100644 --- a/src/core/client/ui/components/Typography/Typography.tsx +++ b/src/core/client/ui/components/Typography/Typography.tsx @@ -1,8 +1,8 @@ import cn from "classnames"; -import React from "react"; +import React, { Ref } from "react"; import { HTMLAttributes, ReactNode, StatelessComponent } from "react"; -import { withStyles } from "talk-ui/hocs"; +import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; import * as styles from "./Typography.css"; @@ -77,6 +77,12 @@ interface InnerProps extends HTMLAttributes { * Applies the theme typography styles. */ variant?: Variant; + + /** Ref to the root element */ + ref?: Ref; + + /** Internal: Forwarded Ref */ + forwardRef?: Ref; } const Typography: StatelessComponent = props => { @@ -91,6 +97,7 @@ const Typography: StatelessComponent = props => { noWrap, paragraph, variant, + forwardRef, ...rest } = props; @@ -116,7 +123,7 @@ const Typography: StatelessComponent = props => { const Component = component || (paragraph ? "p" : headlineMapping![variant!]) || "span"; - return ; + return ; }; Typography.defaultProps = { @@ -139,6 +146,6 @@ Typography.defaultProps = { variant: "body1", }; -const enhanced = withStyles(styles)(Typography); +const enhanced = withForwardRef(withStyles(styles)(Typography)); export type CenterProps = PropTypesOf; export default enhanced; diff --git a/src/core/client/ui/hocs/index.ts b/src/core/client/ui/hocs/index.ts index 1dd4dbe65..6102cc5ce 100644 --- a/src/core/client/ui/hocs/index.ts +++ b/src/core/client/ui/hocs/index.ts @@ -1,3 +1,4 @@ export { default as withStyles } from "./withStyles"; export { default as withKeyboardFocus } from "./withKeyboardFocus"; export { default as withMouseHover } from "./withMouseHover"; +export { default as withForwardRef } from "./withForwardRef"; diff --git a/src/core/client/ui/hocs/withForwardRef.tsx b/src/core/client/ui/hocs/withForwardRef.tsx new file mode 100644 index 000000000..883923634 --- /dev/null +++ b/src/core/client/ui/hocs/withForwardRef.tsx @@ -0,0 +1,36 @@ +import React, { Ref } from "react"; + +// TODO: ForwardRef API is not supported in enzymes shallow rendering +// https://github.com/airbnb/enzyme/issues/1553 +// As for now we do props passing instead until full React16 support lands in +// enzyme. + +/** + * withForwardRef provides a property called `forwardRef` using + * the `React.forwardRef` api. + */ +/* +function withForwardRef

; forwardRef?: Ref }>( + BaseComponent: React.ComponentType

+): React.ComponentType> { + const forwardRef: RefForwardingComponent = (props, ref) => ( + + ); + return React.forwardRef(forwardRef); +} + +// TODO: workaround, add bug link. +export default withForwardRef as < + P extends { ref?: Ref; forwardRef?: Ref } +>( + BaseComponent: React.ComponentType

+) => React.ComponentType

; + +*/ + +// Stub, currently doesn't do anything except adding types. +export default function withForwardRef

}>( + BaseComponent: React.ComponentType

+): React.ComponentType

{ + return BaseComponent; +} diff --git a/src/core/client/ui/hocs/withKeyboardFocus.tsx b/src/core/client/ui/hocs/withKeyboardFocus.tsx index 00ddc65a6..a3fe33078 100644 --- a/src/core/client/ui/hocs/withKeyboardFocus.tsx +++ b/src/core/client/ui/hocs/withKeyboardFocus.tsx @@ -14,7 +14,7 @@ interface InjectedProps { * to indicate a focus on the element, that wasn't triggered by mouse * or touch. */ -export default hoistStatics( +const withKeyboardFocus = hoistStatics( (WrappedComponent: React.ComponentType) => { class WithKeyboardFocus extends React.Component { public state = { @@ -61,5 +61,9 @@ export default hoistStatics( return WithKeyboardFocus as React.ComponentType; } - // TODO: workaround, add bug link. -) as (WrappedComponent: T) => T; +); + +// TODO: workaround, add bug link. +export default withKeyboardFocus as

>( + WrappedComponent: React.ComponentType

+) => React.ComponentType

; diff --git a/src/core/client/ui/hocs/withMouseHover.tsx b/src/core/client/ui/hocs/withMouseHover.tsx index 8f3b0129a..e181f7bab 100644 --- a/src/core/client/ui/hocs/withMouseHover.tsx +++ b/src/core/client/ui/hocs/withMouseHover.tsx @@ -14,7 +14,7 @@ interface InjectedProps { * to indicate a focus on the element, that wasn't triggered by mouse * or touch. */ -export default hoistStatics( +const withMouseHover = hoistStatics( (WrappedComponent: React.ComponentType) => { class WithMouseHover extends React.Component { public state = { @@ -61,5 +61,9 @@ export default hoistStatics( return WithMouseHover as React.ComponentType; } - // TODO: workaround, add bug link. -) as (WrappedComponent: T) => T; +); + +// TODO: workaround, add bug link. +export default withMouseHover as

>( + WrappedComponent: React.ComponentType

+) => React.ComponentType

;