From 4ec672dda104a7da4ade91b90be5a1fbc316c803 Mon Sep 17 00:00:00 2001 From: Kyle Albert <5498623+kalbert312@users.noreply.github.com> Date: Thu, 25 Jun 2020 13:16:49 -0400 Subject: [PATCH] update(carbon-components-react): 7.10.x - Fix and improve button types, fix forward ref components, simplify UIShell exports. (#45341) * Improve button types. * Simplify exports. * Fix forwardRef types yet again. * Update SecondaryButton. * Update DangerButton. * Update TableBatchAction. * Fix lint errors. Fix some types. --- .../carbon-components-react-tests.tsx | 102 +++++++++++++++++- .../lib/components/Button/Button.d.ts | 94 ++++++++++++---- .../components/DangerButton/DangerButton.d.ts | 18 ++-- .../DataTable/TableBatchAction.d.ts | 12 +-- .../components/ModalWrapper/ModalWrapper.d.ts | 4 +- .../SecondaryButton/SecondaryButton.d.ts | 18 ++-- .../lib/components/UIShell/HeaderMenu.d.ts | 8 +- .../components/UIShell/HeaderMenuItem.d.ts | 11 +- .../lib/components/UIShell/Link.d.ts | 12 +-- .../components/UIShell/SideNavMenuItem.d.ts | 11 +- .../lib/components/UIShell/SwitcherItem.d.ts | 9 +- .../lib/components/UIShell/index.d.ts | 87 +++++---------- .../typings/shared.d.ts | 24 +++-- 13 files changed, 274 insertions(+), 136 deletions(-) diff --git a/types/carbon-components-react/carbon-components-react-tests.tsx b/types/carbon-components-react/carbon-components-react-tests.tsx index 8043111527..c7fde48a94 100644 --- a/types/carbon-components-react/carbon-components-react-tests.tsx +++ b/types/carbon-components-react/carbon-components-react-tests.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { AccordionItem, + Button, Column, DataTable, DataTableCustomRenderProps, @@ -10,9 +11,11 @@ import { Dropdown, HeaderContainer, HeaderMenu, + HeaderMenuItem, FileUploader, NumberInput, Row, + SecondaryButton, Slider, Tab, Table, @@ -24,7 +27,6 @@ import { TooltipDefinition, TextArea, TextInput, - FormItem, FileUploaderDropContainer, FileUploaderItem, MultiSelect, @@ -32,7 +34,8 @@ import { SideNav, SideNavItem, SideNavItems, -} from "carbon-components-react"; + ButtonRenderIconRenderProps, +} from 'carbon-components-react'; import Link from 'carbon-components-react/lib/components/UIShell/Link'; // AccordionItem @@ -53,6 +56,88 @@ const accordionItemTwo = ( ); +// +// Button +// + +const buttonDefaultT1 = ( + +); + +const buttonRef = React.useRef(null); +const SimpleButtonIcon = () =>
; +const buttonDefaultT2 = ( + +); + +const buttonIconT1 = ( + +); +// TODO: find a way to make this fail because someProp is required by the component but it will never be provided. +const IconWithProps: React.FC<{ someProp: number, anotherProp?: string }> = () =>
; +const buttonIconT2 = ( + +); + +const buttonIconT3 = ( + +); + +const anchorRef = React.useRef(null); +const buttonAnchorT1 = ( + +); + +const spanRef = React.useRef(null); +const buttonIntrinsicT1 = ( + +); + +const ButtonCustomRenderComp1: React.FC<{ someProp: number, anotherProp?: string }> = () =>
; + +const buttonCustomRenderT1 = ( + +); + +// +// SecondaryButton +// +const secondaryButtonT1 = ( + event.preventDefault()}>Secondary +); +const secondaryButtonT2 = ( + event.preventDefault()}>Secondary +); +const secondaryButtonT3 = ( + Secondary +) + interface Row1 extends DataTableRow { rowProp: string; } @@ -285,6 +370,7 @@ const uisHeaderContainerCompRenderNotMatchingRequiredProps = ; // UI Shell - HeaderMenu + const uisHeaderMenuAnonRender = (
}>
@@ -303,6 +389,18 @@ const uisHeaderMenuCompRenderNotMatchingOptionalProps = ( ); +// +// HeaderMenuItem +// + +const uisHeaderMenuItemRequiredChild = ( + Required Child +); + +// +// UIShell Link +// + interface TestCompPropsOverwrite { element?: 'overwriteTest'; // making this required will produce an error. The underlying component will never receive prop element so it's not allowed to be required. someProp: string; diff --git a/types/carbon-components-react/lib/components/Button/Button.d.ts b/types/carbon-components-react/lib/components/Button/Button.d.ts index 282b478a2f..009f29a486 100644 --- a/types/carbon-components-react/lib/components/Button/Button.d.ts +++ b/types/carbon-components-react/lib/components/Button/Button.d.ts @@ -1,30 +1,86 @@ import * as React from "react"; -import { EmbeddedIconProps, EmbeddedTooltipProps, ReactAnchorAttr, ReactButtonAttr, ReactCreateElementParam, RenderIconProps, SizingProps, } from "../../../typings/shared"; +import { + EmbeddedIconProps, + EmbeddedTooltipProps, + ReactButtonAttr, + FCReturn, JSXIntrinsicElementProps, ReactAnchorAttr, ForwardRefProps, +} from '../../../typings/shared'; export type ButtonKind = "danger" | "danger--primary" | "ghost" | "primary" | "secondary" | "tertiary"; export type ButtonSize = "default" | "field" | "small"; -interface InheritedButtonProps extends ReactButtonAttr { } - -interface InheritedAnchorProps extends ReactAnchorAttr { } - -interface SharedProps extends - EmbeddedIconProps, - EmbeddedTooltipProps, - RenderIconProps, - SizingProps -{ - as?: ReactCreateElementParam, - hasIconOnly?: boolean, - kind?: ButtonKind, // required but has default value - size?: ButtonSize, +export interface ButtonRenderIconRenderProps { + "aria-hidden"?: boolean; + "aria-label"?: EmbeddedIconProps["iconDescription"]; + className?: string; } -export interface ButtonProps extends SharedProps, InheritedButtonProps { } +// this is split due to a typing issue with the specialized buttons (SecondaryButton, etc) +interface ButtonKindProps { + kind?: ButtonKind; // required by has default value +} -export interface ButtonAnchorProps extends SharedProps, InheritedAnchorProps { } +// these props are not passed to the general createElement call +interface ButtonBaseIsolatedProps extends EmbeddedIconProps, EmbeddedTooltipProps { + hasIconOnly?: boolean; + // trying to type this just causes problems around inference, overload selection, and anon fn vs typed component references. + // if anon render props type is desired, import ButtonRenderIconRenderProps. + renderIcon?: any; + size?: ButtonSize; + /** + * @deprecated + */ + small?: boolean; +} +type SafeProps

= Omit; -export type AllButtonProps = ButtonAnchorProps | ButtonProps; -declare const Button: React.RefForwardingComponent; +interface ButtonBaseProps extends ButtonBaseIsolatedProps { + children?: React.ReactNode; + className?: string; + disabled?: boolean; +} + +export interface ButtonDefaultProps extends ButtonBaseProps, ReactButtonAttr { + as?: undefined; + href?: undefined; +} +// alias for old type that used to be exported +export type ButtonProps = ButtonDefaultProps; + +export interface ButtonAnchorProps extends ButtonBaseProps, Omit { + as?: undefined; + href: string; +} + +export type ButtonIntrinsicProps = ButtonBaseProps & + SafeProps> & { + as: K; + }; + +export type ButtonCustomComponentProps< + C extends React.JSXElementConstructor +> = C extends React.JSXElementConstructor + ? ButtonBaseProps & + SafeProps

& { + as: C; + } + : never; + +// +// Note: TypeScript will try to select the best overload but this is not always easily predictable the more freedom the +// generic types have or the more they overlap. If you're having difficulty with these types you can try reexporting the +// component casted to your desired type. +// ex: +// import { Button } from "carbon-components-react" +// export const DefaultButton = Button as React.FC; +// export const AnchorButton = Button as React.FC; +// +// or just create a wrapper component. +// +declare function Button(props: ForwardRefProps): FCReturn; +// tslint:disable:unified-signatures breaks certain usages +declare function Button(props: ForwardRefProps): FCReturn; +declare function Button(props: ForwardRefProps & ButtonKindProps>): FCReturn; +declare function Button, R = unknown>(props: ForwardRefProps & ButtonKindProps>): FCReturn; export default Button; diff --git a/types/carbon-components-react/lib/components/DangerButton/DangerButton.d.ts b/types/carbon-components-react/lib/components/DangerButton/DangerButton.d.ts index 0e7c4e1449..4a2b77faf0 100644 --- a/types/carbon-components-react/lib/components/DangerButton/DangerButton.d.ts +++ b/types/carbon-components-react/lib/components/DangerButton/DangerButton.d.ts @@ -1,10 +1,16 @@ import * as React from "react"; -import { ButtonProps } from "../Button"; +import { + ButtonAnchorProps, + ButtonDefaultProps, + ButtonIntrinsicProps, + ButtonCustomComponentProps, +} from '../Button'; +import { FCReturn, FCProps } from '../../../typings/shared'; -interface InheritedProps extends Omit { } - -export interface DangerButtonProps extends InheritedProps { } - -declare const DangerButton: React.FC; +declare function DangerButton(props: FCProps): FCReturn; +// tslint:disable:unified-signatures breaks certain usages +declare function DangerButton(props: FCProps): FCReturn; +declare function DangerButton(props: FCProps>): FCReturn; +declare function DangerButton>(props: FCProps>): FCReturn; export default DangerButton; diff --git a/types/carbon-components-react/lib/components/DataTable/TableBatchAction.d.ts b/types/carbon-components-react/lib/components/DataTable/TableBatchAction.d.ts index 3bac419c51..eb8d9b026f 100644 --- a/types/carbon-components-react/lib/components/DataTable/TableBatchAction.d.ts +++ b/types/carbon-components-react/lib/components/DataTable/TableBatchAction.d.ts @@ -1,10 +1,4 @@ -import * as React from "react"; -import { ButtonProps } from "../Button"; +import Button from "../Button"; -interface InheritedProps extends ButtonProps { } - -export interface TableBatchActionProps extends InheritedProps { } - -declare const TableBatchAction: React.FC; - -export default TableBatchAction; +// It's the same thing except it has different default props. +export default Button; diff --git a/types/carbon-components-react/lib/components/ModalWrapper/ModalWrapper.d.ts b/types/carbon-components-react/lib/components/ModalWrapper/ModalWrapper.d.ts index 3923b320e1..2bec2b9024 100644 --- a/types/carbon-components-react/lib/components/ModalWrapper/ModalWrapper.d.ts +++ b/types/carbon-components-react/lib/components/ModalWrapper/ModalWrapper.d.ts @@ -1,5 +1,5 @@ import * as React from "react"; -import { ButtonProps } from "../Button"; +import { ButtonProps, ButtonKind } from '../Button'; import { ModalProps } from "../Modal"; type ExcludedModalProps = "onRequestClose" | "onRequestSubmit" | "open"; @@ -10,7 +10,7 @@ export interface TriggerProps { buttonTriggerText?: ButtonProps["children"], renderTriggerButtonIcon?: ButtonProps["renderIcon"], triggerButtonIconDescription?: ButtonProps["iconDescription"], - triggerButtonKind?: ButtonProps["kind"], + triggerButtonKind?: ButtonKind, } export interface ModalWrapperProps extends InheritedProps, TriggerProps { diff --git a/types/carbon-components-react/lib/components/SecondaryButton/SecondaryButton.d.ts b/types/carbon-components-react/lib/components/SecondaryButton/SecondaryButton.d.ts index b4f53dee70..84d1c9dc8c 100644 --- a/types/carbon-components-react/lib/components/SecondaryButton/SecondaryButton.d.ts +++ b/types/carbon-components-react/lib/components/SecondaryButton/SecondaryButton.d.ts @@ -1,10 +1,16 @@ import * as React from "react"; -import { ButtonProps } from "../Button"; +import { + ButtonAnchorProps, + ButtonDefaultProps, + ButtonIntrinsicProps, + ButtonCustomComponentProps, +} from '../Button'; +import { FCReturn, FCProps } from '../../../typings/shared'; -interface InheritedProps extends Omit { } - -export interface SecondaryButtonProps extends InheritedProps { } - -declare const SecondaryButton: React.FC; +declare function SecondaryButton(props: FCProps): FCReturn; +// tslint:disable:unified-signatures breaks certain usages +declare function SecondaryButton(props: FCProps): FCReturn; +declare function SecondaryButton(props: FCProps>): FCReturn; +declare function SecondaryButton>(props: FCProps>): FCReturn; export default SecondaryButton; diff --git a/types/carbon-components-react/lib/components/UIShell/HeaderMenu.d.ts b/types/carbon-components-react/lib/components/UIShell/HeaderMenu.d.ts index 67857e279a..d174f0ddfb 100644 --- a/types/carbon-components-react/lib/components/UIShell/HeaderMenu.d.ts +++ b/types/carbon-components-react/lib/components/UIShell/HeaderMenu.d.ts @@ -1,5 +1,5 @@ import * as React from "react"; -import { ReactAttr, ForwardRefRefType, FCReturn, FCProps } from "../../../typings/shared"; +import { ReactAttr, FCReturn } from '../../../typings/shared'; interface InheritedProps { "aria-label"?: ReactAttr["aria-label"], @@ -11,14 +11,12 @@ interface InheritedProps { export interface HeaderMenuProps extends InheritedProps { menuLinkName: string, + ref?(element: HTMLElement): void; renderMenuContent?: React.ComponentType, } declare class HeaderMenu extends React.Component { } -declare function HeaderMenuForwardRef( - props: FCProps>, - ref: ForwardRefRefType -): FCReturn; +declare function HeaderMenuForwardRef(props: HeaderMenuProps): FCReturn; export default HeaderMenuForwardRef; diff --git a/types/carbon-components-react/lib/components/UIShell/HeaderMenuItem.d.ts b/types/carbon-components-react/lib/components/UIShell/HeaderMenuItem.d.ts index 4bb64edcbb..3371d7cac2 100644 --- a/types/carbon-components-react/lib/components/UIShell/HeaderMenuItem.d.ts +++ b/types/carbon-components-react/lib/components/UIShell/HeaderMenuItem.d.ts @@ -1,4 +1,9 @@ -import { ReactAnchorAttr, RequiresChildrenProps, FCReturn, FCProps, ForwardRefRefType } from "../../../typings/shared"; +import { + ReactAnchorAttr, + RequiresChildrenProps, + FCReturn, + ForwardRefProps, +} from '../../../typings/shared'; import { LinkProps } from "./Link"; type ExcludedAttributes = "children" | "ref" | "tabIndex"; @@ -10,8 +15,8 @@ export interface HeaderMenuItemPropsBase extends InheritedProps { export type HeaderMenuItemProps = Omit, ExcludedAttributes> & HeaderMenuItemPropsBase; -declare function HeaderMenuItem( - props: FCProps>, ref: ForwardRefRefType +declare function HeaderMenuItem( + props: ForwardRefProps> ): FCReturn; export default HeaderMenuItem; diff --git a/types/carbon-components-react/lib/components/UIShell/Link.d.ts b/types/carbon-components-react/lib/components/UIShell/Link.d.ts index f1f2a824a9..5741f30624 100644 --- a/types/carbon-components-react/lib/components/UIShell/Link.d.ts +++ b/types/carbon-components-react/lib/components/UIShell/Link.d.ts @@ -3,10 +3,9 @@ import { Overwrite, ReactAnchorAttr, SideNavSharedProps, - ForwardRefRefType, - FCProps, - FCReturn -} from "../../../typings/shared"; + FCReturn, + ForwardRefProps, +} from '../../../typings/shared'; type InnerElementProps

= Omit; export interface LinkPropsBase

extends SideNavSharedProps { @@ -15,9 +14,8 @@ export interface LinkPropsBase

extends SideNavSharedProps { export type LinkProps

= Overwrite>; -declare function Link

( - props: FCProps>, - ref: ForwardRefRefType +declare function Link

( + props: ForwardRefProps>, ): FCReturn; export default Link; diff --git a/types/carbon-components-react/lib/components/UIShell/SideNavMenuItem.d.ts b/types/carbon-components-react/lib/components/UIShell/SideNavMenuItem.d.ts index 563ddc1a4d..17ae85f5be 100644 --- a/types/carbon-components-react/lib/components/UIShell/SideNavMenuItem.d.ts +++ b/types/carbon-components-react/lib/components/UIShell/SideNavMenuItem.d.ts @@ -1,4 +1,9 @@ -import { ReactAttr, ReactAnchorAttr, FCReturn, FCProps, ForwardRefRefType } from "../../../typings/shared"; +import { + ReactAttr, + ReactAnchorAttr, + FCReturn, + ForwardRefProps, +} from '../../../typings/shared'; import { LinkProps } from "./Link"; interface InheritedProps { @@ -12,8 +17,8 @@ export interface SideNavMenuItemPropsBase extends InheritedProps { export type SideNavMenuItemProps = LinkProps & SideNavMenuItemPropsBase; -declare function SideNavMenuItem( - props: FCProps>, ref: ForwardRefRefType +declare function SideNavMenuItem( + props: ForwardRefProps> ): FCReturn; export default SideNavMenuItem; diff --git a/types/carbon-components-react/lib/components/UIShell/SwitcherItem.d.ts b/types/carbon-components-react/lib/components/UIShell/SwitcherItem.d.ts index 9b17f37a13..30f29b8c5c 100644 --- a/types/carbon-components-react/lib/components/UIShell/SwitcherItem.d.ts +++ b/types/carbon-components-react/lib/components/UIShell/SwitcherItem.d.ts @@ -3,9 +3,8 @@ import { ReactAnchorAttr, RequiresChildrenProps, FCReturn, - ForwardRefRefType, - FCProps -} from "../../../typings/shared"; + ForwardRefProps, +} from '../../../typings/shared'; import { LinkProps } from "./Link"; interface InheritedProps extends RequiresChildrenProps { @@ -18,8 +17,8 @@ export interface SwitcherItemPropsBase extends InheritedProps { export type SwitcherItemProps = Omit, "tabIndex"> & SwitcherItemPropsBase; -declare function SwitcherItem( - props: FCProps>, ref: ForwardRefRefType +declare function SwitcherItem( + props: ForwardRefProps> ): FCReturn; export default SwitcherItem; diff --git a/types/carbon-components-react/lib/components/UIShell/index.d.ts b/types/carbon-components-react/lib/components/UIShell/index.d.ts index 4b06ad037a..fc669c2c01 100644 --- a/types/carbon-components-react/lib/components/UIShell/index.d.ts +++ b/types/carbon-components-react/lib/components/UIShell/index.d.ts @@ -1,35 +1,35 @@ -import Content from "./Content"; +export { default as Content } from "./Content"; -import Header from "./Header"; -import HeaderContainer from "./HeaderContainer"; -import HeaderGlobalAction from "./HeaderGlobalAction"; -import HeaderGlobalBar from "./HeaderGlobalBar"; -import HeaderMenu from "./HeaderMenu"; -import HeaderMenuButton from "./HeaderMenuButton"; -import HeaderMenuItem from "./HeaderMenuItem"; -import HeaderName from "./HeaderName"; -import HeaderNavigation from "./HeaderNavigation"; -import HeaderPanel from "./HeaderPanel"; -import HeaderSideNavItems from "./HeaderSideNavItems"; +export { default as Header } from "./Header"; +export { default as HeaderContainer } from "./HeaderContainer"; +export { default as HeaderGlobalAction } from "./HeaderGlobalAction"; +export { default as HeaderGlobalBar } from "./HeaderGlobalBar"; +export { default as HeaderMenu } from "./HeaderMenu"; +export { default as HeaderMenuButton } from "./HeaderMenuButton"; +export { default as HeaderMenuItem } from "./HeaderMenuItem"; +export { default as HeaderName } from "./HeaderName"; +export { default as HeaderNavigation } from "./HeaderNavigation"; +export { default as HeaderPanel } from "./HeaderPanel"; +export { default as HeaderSideNavItems } from "./HeaderSideNavItems"; -import SideNav from "./SideNav"; -import SideNavDetails from "./SideNavDetails"; -import SideNavFooter from "./SideNavFooter"; -import SideNavHeader from "./SideNavHeader"; -import SideNavIcon from "./SideNavIcon"; -import SideNavItem from "./SideNavItem"; -import SideNavItems from "./SideNavItems"; -import SideNavLink from "./SideNavLink"; -import SideNavLinkText from "./SideNavLinkText"; -import SideNavMenu from "./SideNavMenu"; -import SideNavMenuItem from "./SideNavMenuItem"; -import SideNavSwitcher from "./SideNavSwitcher"; +export { default as SideNav } from "./SideNav"; +export { default as SideNavDetails } from "./SideNavDetails"; +export { default as SideNavFooter } from "./SideNavFooter"; +export { default as SideNavHeader } from "./SideNavHeader"; +export { default as SideNavIcon } from "./SideNavIcon"; +export { default as SideNavItem } from "./SideNavItem"; +export { default as SideNavItems } from "./SideNavItems"; +export { default as SideNavLink } from "./SideNavLink"; +export { default as SideNavLinkText } from "./SideNavLinkText"; +export { default as SideNavMenu } from "./SideNavMenu"; +export { default as SideNavMenuItem } from "./SideNavMenuItem"; +export { default as SideNavSwitcher } from "./SideNavSwitcher"; -import SkipToContent from "./SkipToContent"; +export { default as SkipToContent } from "./SkipToContent"; -import Switcher from "./Switcher"; -import SwitcherDivider from "./SwitcherDivider"; -import SwitcherItem from "./SwitcherItem"; +export { default as Switcher } from "./Switcher"; +export { default as SwitcherDivider } from "./SwitcherDivider"; +export { default as SwitcherItem } from "./SwitcherItem"; export * from "./Content"; @@ -63,34 +63,3 @@ export * from "./SkipToContent"; export * from "./Switcher"; export * from "./SwitcherDivider"; export * from "./SwitcherItem"; - -export { - Content, - Header, - HeaderContainer, - HeaderGlobalAction, - HeaderGlobalBar, - HeaderMenu, - HeaderMenuButton, - HeaderMenuItem, - HeaderName, - HeaderNavigation, - HeaderPanel, - HeaderSideNavItems, - SkipToContent, - SideNav, - SideNavDetails, - SideNavFooter, - SideNavHeader, - SideNavIcon, - SideNavItem, - SideNavItems, - SideNavLink, - SideNavLinkText, - SideNavMenu, - SideNavMenuItem, - SideNavSwitcher, - Switcher, - SwitcherDivider, - SwitcherItem -}; diff --git a/types/carbon-components-react/typings/shared.d.ts b/types/carbon-components-react/typings/shared.d.ts index 3128e0b4b1..2fa39f8e0c 100644 --- a/types/carbon-components-react/typings/shared.d.ts +++ b/types/carbon-components-react/typings/shared.d.ts @@ -49,8 +49,8 @@ export interface MenuOffsetData { top?: number; } -export interface RenderIconProps { - renderIcon?: React.ComponentType; +export interface RenderIconProps

{ + renderIcon?: React.ComponentType

; } export interface RequiresChildrenProps { @@ -86,16 +86,20 @@ export interface RefForwardingProps { ref?: React.RefObject; } +// // aliases for some React types that it doesn't export directly. They are needed to make sure we match the signatures -// as close as possible -export type FCReturn = ReturnType; -// IMPORTANT: this type matches what react types has but you MUST add children prop to your prop interface or children -// will be an unknown prop. This is typically not the case for a regular function component. -export type ForwardRefReturn = React.ForwardRefExoticComponent< - React.PropsWithoutRef

& React.RefAttributes ->; +// as close as possible. +// +// reference patterns: +// function component with no generics: export declare const Comp: React.FC; +// function component with generics: export declare function Comp(props: FCProps>): FCReturn; +// forwardRef component with no generics: export declare const Comp: ForwardRefReturn; +// forwardRef component with generics: export declare function Comp(props: ForwardRefProps>): FCReturn; +// export type FCProps

= Parameters>[0]; -export type ForwardRefRefType = Parameters>[1]; +export type FCReturn = ReturnType; +export type ForwardRefProps = React.PropsWithoutRef> & React.RefAttributes; +export type ForwardRefReturn = React.ForwardRefExoticComponent>; export type JSXIntrinsicElementProps< K extends keyof JSX.IntrinsicElements,