diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab7e97d446..0346eaf0d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Update Elastic-Charts to version 13.0.0 and updated the theme object accordingly ([#2381](https://github.com/elastic/eui/pull/2381)) - Added new `EuiColorStops` component ([#2360](https://github.com/elastic/eui/pull/2360)) - Added `currency` glyph to 'EuiIcon' ([#2398](https://github.com/elastic/eui/pull/2398)) +- Migrate `EuiBreadcrumbs`, `EuiHeader` etc, and `EuiLink` to TypeScript ([#2391](https://github.com/elastic/eui/pull/2391)) **Bug fixes** diff --git a/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap b/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.tsx.snap similarity index 91% rename from src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap rename to src/components/breadcrumbs/__snapshots__/breadcrumbs.test.tsx.snap index fc8dc912a5e..b328119bbe4 100644 --- a/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap +++ b/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.tsx.snap @@ -11,18 +11,14 @@ exports[`EuiBreadcrumbs is rendered 1`] = ` data-test-subj="breadcrumbsAnimals" href="#" rel="noreferrer" - title="[object Object]" > - - Animals - + Animals
); }; - -EuiHeaderSectionItem.propTypes = { - border: PropTypes.oneOf(BORDERS), -}; - -EuiHeaderSectionItem.defaultProps = { - border: 'left', -}; diff --git a/src/components/header/header_section/header_section_item_button.test.js b/src/components/header/header_section/header_section_item_button.test.tsx similarity index 83% rename from src/components/header/header_section/header_section_item_button.test.js rename to src/components/header/header_section/header_section_item_button.test.tsx index e972ab20091..817519bf34f 100644 --- a/src/components/header/header_section/header_section_item_button.test.js +++ b/src/components/header/header_section/header_section_item_button.test.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { render, shallow } from 'enzyme'; -import sinon from 'sinon'; import { requiredProps } from '../../../test/required_props'; import { EuiHeaderSectionItemButton } from './header_section_item_button'; @@ -24,15 +23,15 @@ describe('EuiHeaderSectionItemButton', () => { describe('onClick', () => { test("isn't called upon instantiation", () => { - const onClickHandler = sinon.stub(); + const onClickHandler = jest.fn(); shallow(); - sinon.assert.notCalled(onClickHandler); + expect(onClickHandler).not.toHaveBeenCalled(); }); test('is called when the button is clicked', () => { - const onClickHandler = sinon.stub(); + const onClickHandler = jest.fn(); const $button = shallow( @@ -40,7 +39,7 @@ describe('EuiHeaderSectionItemButton', () => { $button.simulate('click'); - sinon.assert.calledOnce(onClickHandler); + expect(onClickHandler).toHaveBeenCalledTimes(1); }); }); }); diff --git a/src/components/header/header_section/header_section_item_button.js b/src/components/header/header_section/header_section_item_button.tsx similarity index 53% rename from src/components/header/header_section/header_section_item_button.js rename to src/components/header/header_section/header_section_item_button.tsx index e740f7405f7..413c288a479 100644 --- a/src/components/header/header_section/header_section_item_button.js +++ b/src/components/header/header_section/header_section_item_button.tsx @@ -1,8 +1,11 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React, { ButtonHTMLAttributes, FunctionComponent } from 'react'; import classNames from 'classnames'; -export const EuiHeaderSectionItemButton = ({ +import { CommonProps } from '../../common'; + +type Props = CommonProps & ButtonHTMLAttributes; + +export const EuiHeaderSectionItemButton: FunctionComponent = ({ onClick, children, className, @@ -16,7 +19,3 @@ export const EuiHeaderSectionItemButton = ({ ); }; - -EuiHeaderSectionItemButton.propTypes = { - onClick: PropTypes.func, -}; diff --git a/src/components/header/header_section/index.js b/src/components/header/header_section/index.ts similarity index 100% rename from src/components/header/header_section/index.js rename to src/components/header/header_section/index.ts diff --git a/src/components/header/index.d.ts b/src/components/header/index.d.ts deleted file mode 100644 index 68df664fc81..00000000000 --- a/src/components/header/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { - EuiHeaderLogoProps as HeaderLogoProps, - EuiHeaderLogo as HeaderLogo, -} from './header_logo'; - -declare module '@elastic/eui' { - /** - * header logo type defs - * - * @see './header_logo.js' - */ - export interface EuiHeaderLogoProps extends HeaderLogoProps {} - export const EuiHeaderLogo: typeof HeaderLogo; -} diff --git a/src/components/header/index.js b/src/components/header/index.ts similarity index 55% rename from src/components/header/index.js rename to src/components/header/index.ts index 733f3cc5d0f..731612722e6 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.ts @@ -1,12 +1,12 @@ -export { EuiHeader } from './header'; +export { EuiHeader, EuiHeaderProps } from './header'; -export { EuiHeaderAlert } from './header_alert'; +export { EuiHeaderAlert, EuiHeaderAlertProps } from './header_alert'; export { EuiHeaderBreadcrumbs } from './header_breadcrumbs'; export { EuiHeaderLink, EuiHeaderLinks } from './header_links'; -export { EuiHeaderLogo } from './header_logo'; +export { EuiHeaderLogo, EuiHeaderLogoProps } from './header_logo'; export { EuiHeaderSection, diff --git a/src/components/index.d.ts b/src/components/index.d.ts index f803fd77da4..0e67f175797 100644 --- a/src/components/index.d.ts +++ b/src/components/index.d.ts @@ -5,8 +5,6 @@ /// /// /// -/// -/// /// /// /// diff --git a/src/components/link/__snapshots__/link.test.js.snap b/src/components/link/__snapshots__/link.test.tsx.snap similarity index 100% rename from src/components/link/__snapshots__/link.test.js.snap rename to src/components/link/__snapshots__/link.test.tsx.snap diff --git a/src/components/link/index.d.ts b/src/components/link/index.d.ts deleted file mode 100644 index 07ef636fa80..00000000000 --- a/src/components/link/index.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { CommonProps, Omit } from '../common'; - -import { - FunctionComponent, - AnchorHTMLAttributes, - ButtonHTMLAttributes, - MouseEventHandler, -} from 'react'; - -declare module '@elastic/eui' { - /** - * link type defs - * - * @see './link.js' - */ - - export type EuiLinkType = 'button' | 'reset' | 'submit'; - export type EuiLinkColor = - | 'primary' - | 'subdued' - | 'secondary' - | 'accent' - | 'danger' - | 'warning' - | 'text' - | 'ghost'; - - export interface LinkButtonProps { - type?: EuiLinkType; - color?: EuiLinkColor; - onClick?: MouseEventHandler; - } - - type EuiLinkButtonProps = CommonProps & - ButtonHTMLAttributes & - LinkButtonProps; - - export interface LinkAnchorProps { - type?: EuiLinkType; - color?: EuiLinkColor; - } - - type EuiLinkAnchorProps = CommonProps & - Omit, 'onClick'> & - LinkAnchorProps; - - export const EuiLink: FunctionComponent< - EuiLinkButtonProps | EuiLinkAnchorProps - >; -} diff --git a/src/components/link/index.js b/src/components/link/index.js deleted file mode 100644 index 3a643b8217f..00000000000 --- a/src/components/link/index.js +++ /dev/null @@ -1 +0,0 @@ -export { EuiLink } from './link'; diff --git a/src/components/link/index.ts b/src/components/link/index.ts new file mode 100644 index 00000000000..bfcad63b818 --- /dev/null +++ b/src/components/link/index.ts @@ -0,0 +1,6 @@ +export { + EuiLink, + EuiLinkProps, + EuiLinkAnchorProps, + EuiLinkButtonProps, +} from './link'; diff --git a/src/components/link/link.js b/src/components/link/link.js deleted file mode 100644 index 9893138f53a..00000000000 --- a/src/components/link/link.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; - -import { getSecureRelForTarget } from '../../services'; - -const colorsToClassNameMap = { - primary: 'euiLink--primary', - subdued: 'euiLink--subdued', - secondary: 'euiLink--secondary', - accent: 'euiLink--accent', - danger: 'euiLink--danger', - warning: 'euiLink--warning', - ghost: 'euiLink--ghost', - text: 'euiLink--text', -}; - -export const COLORS = Object.keys(colorsToClassNameMap); - -export const EuiLink = ({ - children, - color, - className, - href, - target, - rel, - type, - onClick, - ...rest -}) => { - const classes = classNames('euiLink', colorsToClassNameMap[color], className); - - if (href === undefined) { - return ( - - ); - } - - const secureRel = getSecureRelForTarget({ href, target, rel }); - - return ( - - {children} - - ); -}; - -EuiLink.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - href: PropTypes.string, - target: PropTypes.string, - rel: PropTypes.string, - onClick: PropTypes.func, - type: PropTypes.string, - color: PropTypes.oneOf(COLORS), -}; - -EuiLink.defaultProps = { - color: 'primary', - type: 'button', -}; diff --git a/src/components/link/link.test.js b/src/components/link/link.test.tsx similarity index 97% rename from src/components/link/link.test.js rename to src/components/link/link.test.tsx index 00ee0e5ca80..9aa33738c07 100644 --- a/src/components/link/link.test.js +++ b/src/components/link/link.test.tsx @@ -5,6 +5,7 @@ import { EuiLink, COLORS } from './link'; describe('EuiLink', () => { test('it errors if an invalid color is provided', () => { + // @ts-ignore as we're deliberately using a bogus value expect(() => render()).toThrow(/phooey/); }); diff --git a/src/components/link/link.tsx b/src/components/link/link.tsx new file mode 100644 index 00000000000..8ea458b42fa --- /dev/null +++ b/src/components/link/link.tsx @@ -0,0 +1,120 @@ +import React, { + AnchorHTMLAttributes, + ButtonHTMLAttributes, + MouseEventHandler, + forwardRef, +} from 'react'; +import classNames from 'classnames'; + +import { CommonProps, ExclusiveUnion, keysOf } from '../common'; +import { getSecureRelForTarget } from '../../services'; + +type EuiLinkType = 'button' | 'reset' | 'submit'; +type EuiLinkColor = + | 'primary' + | 'subdued' + | 'secondary' + | 'accent' + | 'danger' + | 'warning' + | 'text' + | 'ghost'; + +const colorsToClassNameMap: { [color in EuiLinkColor]: string } = { + primary: 'euiLink--primary', + subdued: 'euiLink--subdued', + secondary: 'euiLink--secondary', + accent: 'euiLink--accent', + danger: 'euiLink--danger', + warning: 'euiLink--warning', + ghost: 'euiLink--ghost', + text: 'euiLink--text', +}; + +export const COLORS = keysOf(colorsToClassNameMap); + +export interface LinkButtonProps { + type?: EuiLinkType; + color?: EuiLinkColor; + onClick?: MouseEventHandler; +} + +export type EuiLinkButtonProps = CommonProps & + ButtonHTMLAttributes & + LinkButtonProps; + +export interface LinkAnchorProps { + type?: EuiLinkType; + color?: EuiLinkColor; +} + +export type EuiLinkAnchorProps = CommonProps & + AnchorHTMLAttributes & + LinkAnchorProps; + +export type EuiLinkProps = ExclusiveUnion< + EuiLinkButtonProps, + EuiLinkAnchorProps +>; + +const EuiLink = forwardRef( + ( + { + children, + color = 'primary', + className, + href, + target, + rel, + type = 'button', + onClick, + ...rest + }, + ref + ) => { + const classes = classNames( + 'euiLink', + colorsToClassNameMap[color], + className + ); + + if (href === undefined) { + const buttonProps = { + className: classes, + type, + onClick, + ...rest, + }; + + return ( + + ); + } + + const secureRel = getSecureRelForTarget({ href, target, rel }); + + const anchorProps = { + className: classes, + href, + target, + rel: secureRel, + onClick, + ...rest, + }; + + return ( + } + {...anchorProps as EuiLinkAnchorProps}> + {children} + + ); + } +); + +EuiLink.displayName = 'EuiLink'; +export { EuiLink }; diff --git a/src/components/pagination/pagination_button.tsx b/src/components/pagination/pagination_button.tsx index 4ce174e0e06..88c5b5bf52d 100644 --- a/src/components/pagination/pagination_button.tsx +++ b/src/components/pagination/pagination_button.tsx @@ -4,14 +4,14 @@ import classNames from 'classnames'; import { ExclusiveUnion, PropsForAnchor, PropsForButton } from '../common'; import { EuiButtonEmpty, EuiButtonEmptyProps } from '../button'; -export interface EuiPaginationButtonProps extends EuiButtonEmptyProps { +export type EuiPaginationButtonProps = EuiButtonEmptyProps & { isActive?: boolean; /** * For ellipsis or other non-clickable buttons. */ isPlaceholder?: boolean; hideOnMobile?: boolean; -} +}; type EuiPaginationButtonPropsForAnchor = PropsForAnchor< EuiPaginationButtonProps @@ -27,7 +27,6 @@ type Props = ExclusiveUnion< >; export const EuiPaginationButton: FunctionComponent = ({ - children, className, isActive, isPlaceholder, @@ -40,14 +39,13 @@ export const EuiPaginationButton: FunctionComponent = ({ 'euiPaginationButton--hideOnMobile': hideOnMobile, }); - return ( - - {children} - - ); + const props = { + className: classes, + size: 'xs', + color: 'text', + isDisabled: isPlaceholder, + ...rest, + }; + + return ; };