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.
This commit is contained in:
Kyle Albert 2020-06-25 13:16:49 -04:00 committed by GitHub
parent d1564b4f31
commit 4ec672dda1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 274 additions and 136 deletions

View File

@ -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 = (
</AccordionItem>
);
//
// Button
//
const buttonDefaultT1 = (
<Button onClick={(event) => event.preventDefault()}>Basic Button</Button>
);
const buttonRef = React.useRef<HTMLButtonElement>(null);
const SimpleButtonIcon = () => <div/>;
const buttonDefaultT2 = (
<Button
kind="danger"
onClick={(event) => {
event.preventDefault();
}}
renderIcon={SimpleButtonIcon}
ref={buttonRef}
type="reset"
>
Reset
</Button>
);
const buttonIconT1 = (
<Button renderIcon={SimpleButtonIcon}>With Render Icon</Button>
);
// 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 }> = () => <div/>;
const buttonIconT2 = (
<Button renderIcon={IconWithProps}>With Render Icon</Button>
);
const buttonIconT3 = (
<Button renderIcon={({ className }: ButtonRenderIconRenderProps) => <div className={className}/>}>Anon Icon Render</Button>
);
const anchorRef = React.useRef<HTMLAnchorElement>(null);
const buttonAnchorT1 = (
<Button href="https://github.com/DefinitelyTyped/DefinitelyTyped" asdf={"asdf"} target="_blank" ref={anchorRef}>Anchor Link</Button>
);
const spanRef = React.useRef<HTMLSpanElement>(null);
const buttonIntrinsicT1 = (
<Button
as="span"
kind="danger"
onClick={(event) => {
event.preventDefault();
}}
ref={spanRef}
>
Reset
</Button>
);
const ButtonCustomRenderComp1: React.FC<{ someProp: number, anotherProp?: string }> = () => <div/>;
const buttonCustomRenderT1 = (
<Button
as={ButtonCustomRenderComp1}
kind="danger"
someProp={5}
anotherProp="test"
>
Custom Render
</Button>
);
//
// SecondaryButton
//
const secondaryButtonT1 = (
<SecondaryButton onClick={(event) => event.preventDefault()}>Secondary</SecondaryButton>
);
const secondaryButtonT2 = (
<SecondaryButton as="span" onClick={(event) => event.preventDefault()}>Secondary</SecondaryButton>
);
const secondaryButtonT3 = (
<SecondaryButton as={ButtonCustomRenderComp1} someProp={6}>Secondary</SecondaryButton>
)
interface Row1 extends DataTableRow {
rowProp: string;
}
@ -285,6 +370,7 @@ const uisHeaderContainerCompRenderNotMatchingRequiredProps = <HeaderContainer re
const uisHeaderContainerCompRenderNotMatchingOptionalProps = <HeaderContainer render={HeaderCompRender2} />;
// UI Shell - HeaderMenu
const uisHeaderMenuAnonRender = (
<HeaderMenu menuLinkName="test" renderMenuContent={() => <div />}>
<div />
@ -303,6 +389,18 @@ const uisHeaderMenuCompRenderNotMatchingOptionalProps = (
<HeaderMenu menuLinkName="test" renderMenuContent={HeaderCompRender2} />
);
//
// HeaderMenuItem
//
const uisHeaderMenuItemRequiredChild = (
<HeaderMenuItem>Required Child</HeaderMenuItem>
);
//
// 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;

View File

@ -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<P> = Omit<P, 'as' | keyof ButtonBaseIsolatedProps>;
export type AllButtonProps = ButtonAnchorProps | ButtonProps;
declare const Button: React.RefForwardingComponent<HTMLElement, AllButtonProps>;
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<ReactAnchorAttr, "href"> {
as?: undefined;
href: string;
}
export type ButtonIntrinsicProps<K extends keyof JSX.IntrinsicElements> = ButtonBaseProps &
SafeProps<JSXIntrinsicElementProps<K>> & {
as: K;
};
export type ButtonCustomComponentProps<
C extends React.JSXElementConstructor<any>
> = C extends React.JSXElementConstructor<infer P>
? ButtonBaseProps &
SafeProps<P> & {
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<ButtonDefaultProps>;
// export const AnchorButton = Button as React.FC<ButtonAnchorProps>;
//
// or just create a wrapper component.
//
declare function Button(props: ForwardRefProps<HTMLButtonElement, ButtonDefaultProps & ButtonKindProps>): FCReturn;
// tslint:disable:unified-signatures breaks certain usages
declare function Button(props: ForwardRefProps<HTMLAnchorElement, ButtonAnchorProps & ButtonKindProps>): FCReturn;
declare function Button<T extends keyof JSX.IntrinsicElements, R extends HTMLElement = HTMLElement>(props: ForwardRefProps<R, ButtonIntrinsicProps<T> & ButtonKindProps>): FCReturn;
declare function Button<T extends React.JSXElementConstructor<any>, R = unknown>(props: ForwardRefProps<R, ButtonCustomComponentProps<T> & ButtonKindProps>): FCReturn;
export default Button;

View File

@ -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<ButtonProps, "kind"> { }
export interface DangerButtonProps extends InheritedProps { }
declare const DangerButton: React.FC<DangerButtonProps>;
declare function DangerButton(props: FCProps<ButtonDefaultProps>): FCReturn;
// tslint:disable:unified-signatures breaks certain usages
declare function DangerButton(props: FCProps<ButtonAnchorProps>): FCReturn;
declare function DangerButton<T extends keyof JSX.IntrinsicElements>(props: FCProps<ButtonIntrinsicProps<T>>): FCReturn;
declare function DangerButton<T extends React.JSXElementConstructor<any>>(props: FCProps<ButtonCustomComponentProps<T>>): FCReturn;
export default DangerButton;

View File

@ -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<TableBatchActionProps>;
export default TableBatchAction;
// It's the same thing except it has different default props.
export default Button;

View File

@ -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 {

View File

@ -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<ButtonProps, "kind"> { }
export interface SecondaryButtonProps extends InheritedProps { }
declare const SecondaryButton: React.FC<SecondaryButtonProps>;
declare function SecondaryButton(props: FCProps<ButtonDefaultProps>): FCReturn;
// tslint:disable:unified-signatures breaks certain usages
declare function SecondaryButton(props: FCProps<ButtonAnchorProps>): FCReturn;
declare function SecondaryButton<T extends keyof JSX.IntrinsicElements>(props: FCProps<ButtonIntrinsicProps<T>>): FCReturn;
declare function SecondaryButton<T extends React.JSXElementConstructor<any>>(props: FCProps<ButtonCustomComponentProps<T>>): FCReturn;
export default SecondaryButton;

View File

@ -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<RP = {}> extends InheritedProps {
menuLinkName: string,
ref?(element: HTMLElement): void;
renderMenuContent?: React.ComponentType<RP>,
}
declare class HeaderMenu extends React.Component<HeaderMenuProps> { }
declare function HeaderMenuForwardRef<RP = {}>(
props: FCProps<HeaderMenuProps<RP>>,
ref: ForwardRefRefType<HTMLAnchorElement>
): FCReturn;
declare function HeaderMenuForwardRef<RP = {}>(props: HeaderMenuProps<RP>): FCReturn;
export default HeaderMenuForwardRef;

View File

@ -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<E extends object = ReactAnchorAttr> = Omit<LinkProps<E>, ExcludedAttributes> & HeaderMenuItemPropsBase;
declare function HeaderMenuItem<E extends object = ReactAnchorAttr, R extends HTMLElement = HTMLElement>(
props: FCProps<HeaderMenuItemProps<E>>, ref: ForwardRefRefType<R>
declare function HeaderMenuItem<E extends object = ReactAnchorAttr, R = HTMLElement>(
props: ForwardRefProps<R, HeaderMenuItemProps<E>>
): FCReturn;
export default HeaderMenuItem;

View File

@ -3,10 +3,9 @@ import {
Overwrite,
ReactAnchorAttr,
SideNavSharedProps,
ForwardRefRefType,
FCProps,
FCReturn
} from "../../../typings/shared";
FCReturn,
ForwardRefProps,
} from '../../../typings/shared';
type InnerElementProps<P> = Omit<P, "element">;
export interface LinkPropsBase<P = ReactAnchorAttr> extends SideNavSharedProps {
@ -15,9 +14,8 @@ export interface LinkPropsBase<P = ReactAnchorAttr> extends SideNavSharedProps {
export type LinkProps<P extends object = ReactAnchorAttr, IP = P> = Overwrite<P, LinkPropsBase<IP>>;
declare function Link<P extends object = ReactAnchorAttr>(
props: FCProps<LinkProps<P>>,
ref: ForwardRefRefType<HTMLElement>
declare function Link<P extends object = ReactAnchorAttr, R = HTMLAnchorElement>(
props: ForwardRefProps<R, LinkProps<P>>,
): FCReturn;
export default Link;

View File

@ -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<E extends object = ReactAnchorAttr> = LinkProps<E> & SideNavMenuItemPropsBase;
declare function SideNavMenuItem<E extends object = ReactAnchorAttr, R extends HTMLElement = HTMLElement>(
props: FCProps<SideNavMenuItemProps<E>>, ref: ForwardRefRefType<R>
declare function SideNavMenuItem<E extends object = ReactAnchorAttr, R = HTMLElement>(
props: ForwardRefProps<R, SideNavMenuItemProps<E>>
): FCReturn;
export default SideNavMenuItem;

View File

@ -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<E extends object = ReactAnchorAttr> = Omit<LinkProps<E>, "tabIndex"> & SwitcherItemPropsBase;
declare function SwitcherItem<E extends object = ReactAnchorAttr, R extends HTMLElement = HTMLElement>(
props: FCProps<SwitcherItemProps<E>>, ref: ForwardRefRefType<R>
declare function SwitcherItem<E extends object = ReactAnchorAttr, R = HTMLElement>(
props: ForwardRefProps<R, SwitcherItemProps<E>>
): FCReturn;
export default SwitcherItem;

View File

@ -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
};

View File

@ -49,8 +49,8 @@ export interface MenuOffsetData {
top?: number;
}
export interface RenderIconProps {
renderIcon?: React.ComponentType;
export interface RenderIconProps<P = any> {
renderIcon?: React.ComponentType<P>;
}
export interface RequiresChildrenProps<T = React.ReactNode> {
@ -86,16 +86,20 @@ export interface RefForwardingProps<T = HTMLElement> {
ref?: React.RefObject<T>;
}
//
// 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<React.FC>;
// 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<T, P = {}> = React.ForwardRefExoticComponent<
React.PropsWithoutRef<P> & React.RefAttributes<T>
>;
// as close as possible.
//
// reference patterns:
// function component with no generics: export declare const Comp: React.FC<PropsInterface>;
// function component with generics: export declare function Comp<T extends SomeType>(props: FCProps<PropsInterface<T>>): FCReturn;
// forwardRef component with no generics: export declare const Comp: ForwardRefReturn<HTMLElement, PropsInterface>;
// forwardRef component with generics: export declare function Comp<T extends SomeType>(props: ForwardRefProps<PropsInterface<T>>): FCReturn;
//
export type FCProps<P = {}> = Parameters<React.FC<P>>[0];
export type ForwardRefRefType<T> = Parameters<React.ForwardRefRenderFunction<T, unknown>>[1];
export type FCReturn = ReturnType<React.FC>;
export type ForwardRefProps<T, P = {}> = React.PropsWithoutRef<React.PropsWithChildren<P>> & React.RefAttributes<T>;
export type ForwardRefReturn<T, P = {}> = React.ForwardRefExoticComponent<ForwardRefProps<T, P>>;
export type JSXIntrinsicElementProps<
K extends keyof JSX.IntrinsicElements,