Skip to content

Commit

Permalink
TS button onClick clean up (#2282)
Browse files Browse the repository at this point in the history
* button onclick clean up

* clickable generics

* CL
  • Loading branch information
thompsongl authored Sep 4, 2019
1 parent 6cffa27 commit 7cc470f
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 40 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

**Bug fixes**

- Removed extra right side margin in 'EuiSuperDatePicker' ([#2236](https://github.com/elastic/eui/pull/2236))
- Removed extra right side margin in `EuiSuperDatePicker` ([#2236](https://github.com/elastic/eui/pull/2236))
- Fix incorrect `onClick` type for `EuiButtonEmpty` ([#2282](https://github.com/elastic/eui/pull/2282))

## [`13.7.0`](https://github.com/elastic/eui/tree/v13.7.0)

Expand Down
28 changes: 17 additions & 11 deletions src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ import React, {
ButtonHTMLAttributes,
FunctionComponent,
HTMLAttributes,
MouseEventHandler,
Ref,
} from 'react';
import classNames from 'classnames';

import { CommonProps, ExclusiveUnion, keysOf } from '../common';
import {
CommonProps,
ExclusiveUnion,
PropsForAnchor,
PropsForButton,
keysOf,
} from '../common';
import { EuiLoadingSpinner } from '../loading';

import { getSecureRelForTarget } from '../../services';
Expand Down Expand Up @@ -65,18 +70,19 @@ export interface EuiButtonProps extends CommonProps {
textProps?: HTMLAttributes<HTMLSpanElement>;
}

type EuiButtonPropsForAnchor = EuiButtonProps &
AnchorHTMLAttributes<HTMLAnchorElement> & {
href?: string;
onClick?: MouseEventHandler<HTMLAnchorElement>;
type EuiButtonPropsForAnchor = PropsForAnchor<
EuiButtonProps,
{
buttonRef?: Ref<HTMLAnchorElement>;
};
}
>;

type EuiButtonPropsForButton = EuiButtonProps &
ButtonHTMLAttributes<HTMLButtonElement> & {
onClick?: MouseEventHandler<HTMLButtonElement>;
type EuiButtonPropsForButton = PropsForButton<
EuiButtonProps,
{
buttonRef?: Ref<HTMLButtonElement>;
};
}
>;

export type Props = ExclusiveUnion<
EuiButtonPropsForAnchor,
Expand Down
24 changes: 18 additions & 6 deletions src/components/button/button_empty/button_empty.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import React, { FunctionComponent, HTMLAttributes } from 'react';
import classNames from 'classnames';

import { CommonProps, keysOf, NoArgCallback } from '../../common';
import {
CommonProps,
ExclusiveUnion,
PropsForAnchor,
PropsForButton,
keysOf,
} from '../../common';
import { EuiLoadingSpinner } from '../../loading';
import { getSecureRelForTarget } from '../../../services';
import { IconType, EuiIcon } from '../../icon';
Expand Down Expand Up @@ -38,7 +44,7 @@ const flushTypeToClassNameMap = {

export const FLUSH_TYPES = keysOf(flushTypeToClassNameMap);

export interface EuiButtonEmptyProps {
export interface EuiButtonEmptyProps extends CommonProps {
iconType?: IconType;
iconSide?: keyof typeof iconSideToClassNameMap;
color?: keyof typeof colorToClassNameMap;
Expand All @@ -48,7 +54,6 @@ export interface EuiButtonEmptyProps {
href?: string;
target?: string;
rel?: string;
onClick?: NoArgCallback<void>;

/**
* Adds/swaps for loading spinner & disables
Expand All @@ -68,7 +73,14 @@ export interface EuiButtonEmptyProps {
textProps?: Partial<HTMLAttributes<HTMLSpanElement>>;
}

type Props = CommonProps & EuiButtonEmptyProps;
type EuiButtonEmptyPropsForAnchor = PropsForAnchor<EuiButtonEmptyProps>;

type EuiButtonEmptyPropsForButton = PropsForButton<EuiButtonEmptyProps>;

type Props = ExclusiveUnion<
EuiButtonEmptyPropsForAnchor,
EuiButtonEmptyPropsForButton
>;

export const EuiButtonEmpty: FunctionComponent<Props> = ({
children,
Expand Down Expand Up @@ -148,7 +160,7 @@ export const EuiButtonEmpty: FunctionComponent<Props> = ({
target={target}
rel={secureRel}
ref={buttonRef}
{...rest}>
{...rest as EuiButtonEmptyPropsForAnchor}>
{innerNode}
</a>
);
Expand All @@ -160,7 +172,7 @@ export const EuiButtonEmpty: FunctionComponent<Props> = ({
className={classes}
type={type}
ref={buttonRef}
{...rest}>
{...rest as EuiButtonEmptyPropsForButton}>
{innerNode}
</button>
);
Expand Down
28 changes: 17 additions & 11 deletions src/components/button/button_icon/button_icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import React, {
AnchorHTMLAttributes,
ButtonHTMLAttributes,
FunctionComponent,
MouseEventHandler,
Ref,
} from 'react';
import classNames from 'classnames';

import { getSecureRelForTarget } from '../../../services';
import { CommonProps, ExclusiveUnion, keysOf } from '../../common';
import {
CommonProps,
ExclusiveUnion,
PropsForAnchor,
PropsForButton,
keysOf,
} from '../../common';

import { IconType, IconSize, EuiIcon } from '../../icon';

Expand All @@ -34,18 +39,19 @@ export interface EuiButtonIconProps extends CommonProps {
iconSize?: IconSize;
}

type EuiButtonIconPropsForAnchor = EuiButtonIconProps &
AnchorHTMLAttributes<HTMLAnchorElement> & {
href: string;
onClick?: MouseEventHandler<HTMLAnchorElement>;
type EuiButtonIconPropsForAnchor = PropsForAnchor<
EuiButtonIconProps,
{
buttonRef?: Ref<HTMLAnchorElement>;
};
}
>;

export type EuiButtonIconPropsForButton = EuiButtonIconProps &
ButtonHTMLAttributes<HTMLButtonElement> & {
onClick?: MouseEventHandler<HTMLButtonElement>;
export type EuiButtonIconPropsForButton = PropsForButton<
EuiButtonIconProps,
{
buttonRef?: Ref<HTMLButtonElement>;
};
}
>;

type Props = ExclusiveUnion<
EuiButtonIconPropsForAnchor,
Expand Down
32 changes: 31 additions & 1 deletion src/components/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Component, FunctionComponent, SFC } from 'react';
import {
AnchorHTMLAttributes,
ButtonHTMLAttributes,
Component,
FunctionComponent,
MouseEventHandler,
SFC,
} from 'react';

export interface CommonProps {
className?: string;
Expand Down Expand Up @@ -110,3 +117,26 @@ export type DisambiguateSet<T, U> = {
export type ExclusiveUnion<T, U> = (T | U) extends object // if there are any shared keys between T and U
? (DisambiguateSet<T, U> & U) | (DisambiguateSet<U, T> & T) // otherwise the TS union is already unique
: T | U;

/**
* For components that conditionally render <button> or <a>
* Convenience types for extending base props (T) and
* element-specific props (P) with standard clickable properties
*
* These will likely be used together, along with `ExclusiveUnion`:
*
* type AnchorLike = PropsForAnchor<BaseProps>
* type ButtonLike = PropsForButton<BaseProps>
* type ComponentProps = ExlcusiveUnion<AnchorLike, ButtonLike>
* const Component: FunctionComponent<ComponentProps> ...
*/
export type PropsForAnchor<T, P = {}> = T &
AnchorHTMLAttributes<HTMLAnchorElement> & {
href?: string;
onClick?: MouseEventHandler<HTMLAnchorElement>;
} & P;

export type PropsForButton<T, P = {}> = T &
ButtonHTMLAttributes<HTMLButtonElement> & {
onClick?: MouseEventHandler<HTMLButtonElement>;
} & P;
20 changes: 15 additions & 5 deletions src/components/filter_group/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Component, FunctionComponent, ButtonHTMLAttributes } from 'react';

import { CommonProps } from '../common';
import {
CommonProps,
ExclusiveUnion,
PropsForAnchor,
PropsForButton,
} from '../common';
import { EuiButtonEmptyProps } from '../button';
import { EuiFilterGroupProps } from './filter_group';

Expand All @@ -11,23 +16,28 @@ declare module '@elastic/eui' {
* @see './filter_button.js'
*/

export interface EuiFilterButtonProps {
export interface EuiFilterButtonProps extends EuiButtonEmptyProps {
numFilters?: number;
numActiveFilters?: number;
hasActiveFilters?: boolean;
isSelected?: boolean;
isDisabled?: boolean;
type?: string;
grow?: boolean;
withNext?: boolean;
/**
* _DEPRECATED use `withNext`_
*/
noDivider?: boolean;
}
export const EuiFilterButton: FunctionComponent<
EuiButtonEmptyProps & EuiFilterButtonProps
type EuiFilterButtonPropsForAnchor = PropsForAnchor<EuiFilterButtonProps>;

type EuiFilterButtonPropsForButton = PropsForButton<EuiFilterButtonProps>;

type Props = ExclusiveUnion<
EuiFilterButtonPropsForAnchor,
EuiFilterButtonPropsForButton
>;
export const EuiFilterButton: FunctionComponent<Props>;

/**
* Filter group type defs
Expand Down
19 changes: 14 additions & 5 deletions src/components/pagination/pagination_button.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { FunctionComponent } from 'react';
import classNames from 'classnames';

import { CommonProps, Omit } from '../common';
import { ExclusiveUnion, PropsForAnchor, PropsForButton } from '../common';
import { EuiButtonEmpty, EuiButtonEmptyProps } from '../button';

export interface EuiPaginationButtonProps {
export interface EuiPaginationButtonProps extends EuiButtonEmptyProps {
isActive?: boolean;
/**
* For ellipsis or other non-clickable buttons.
Expand All @@ -13,9 +13,18 @@ export interface EuiPaginationButtonProps {
hideOnMobile?: boolean;
}

type Props = CommonProps &
Omit<EuiButtonEmptyProps, 'size' | 'color'> &
EuiPaginationButtonProps;
type EuiPaginationButtonPropsForAnchor = PropsForAnchor<
EuiPaginationButtonProps
>;

type EuiPaginationButtonPropsForButton = PropsForButton<
EuiPaginationButtonProps
>;

type Props = ExclusiveUnion<
EuiPaginationButtonPropsForAnchor,
EuiPaginationButtonPropsForButton
>;

export const EuiPaginationButton: FunctionComponent<Props> = ({
children,
Expand Down

0 comments on commit 7cc470f

Please sign in to comment.