Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiFlyout] Refactor polymorphic types #4940

Merged
merged 5 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `35.1.0`.
- Refactored `EuiFlyout` types ([#4940](https://github.com/elastic/eui/pull/4940))

## [`35.1.0`](https://github.com/elastic/eui/tree/v35.1.0)

Expand Down
5 changes: 5 additions & 0 deletions src/components/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export type PropsOf<C> = C extends SFC<infer SFCProps>
? ComponentProps
: never;

// Returns the props of a given HTML element
export type PropsOfElement<
C extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<C, React.ComponentProps<C>>;

// Utility methods for ApplyClassComponentDefaults
type ExtractDefaultProps<T> = T extends { defaultProps: infer D } ? D : never;
type ExtractProps<
Expand Down
56 changes: 27 additions & 29 deletions src/components/flyout/flyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import React, {
forwardRef,
CSSProperties,
Fragment,
ComponentType,
FunctionComponent,
ComponentPropsWithRef,
PropsWithChildren,
MutableRefObject,
} from 'react';
import classnames from 'classnames';
Expand All @@ -28,7 +27,7 @@ import {
throttle,
} from '../../services';

import { CommonProps, keysOf } from '../common';
import { CommonProps, keysOf, PropsOfElement } from '../common';
import { EuiFocusTrap } from '../focus_trap';
import { EuiOverlayMask, EuiOverlayMaskProps } from '../overlay_mask';
import { EuiButtonIcon, EuiButtonIconPropsForButton } from '../button';
Expand Down Expand Up @@ -153,32 +152,26 @@ type _EuiFlyoutProps = {
style?: React.CSSProperties;
};

// Using ReactHTML rather than JSX.IntrinsicElements here because it does not include
// SVG element types which cause errors because they do not have all the attributes needed.
type ComponentTypes =
| 'div'
| 'span'
| 'nav'
| 'aside'
| 'section'
| 'article'
| 'header'
| ComponentType;

export type EuiFlyoutProps<T extends ComponentTypes = 'div'> = CommonProps &
ComponentPropsWithRef<T> & {
/**
* Sets the HTML element for `EuiFlyout`
*/
as?: T;
} & _EuiFlyoutProps;
const defaultElement = 'div';

type Props<T extends React.ElementType> = CommonProps & {
/**
* Sets the HTML element for `EuiFlyout`
*/
as?: T;
} & _EuiFlyoutProps &
Omit<PropsOfElement<T>, keyof _EuiFlyoutProps>;

export type EuiFlyoutProps<
T extends React.ElementType = typeof defaultElement
> = Props<T> & Omit<ComponentPropsWithRef<T>, keyof Props<T>>;

const EuiFlyout = forwardRef(
<T extends ComponentTypes>(
<T extends React.ElementType = typeof defaultElement>(
{
className,
children,
as: Element = 'div' as T,
as,
hideCloseButton = false,
closeButtonProps,
closeButtonAriaLabel,
Expand All @@ -196,12 +189,13 @@ const EuiFlyout = forwardRef(
role = 'dialog',
pushMinBreakpoint = 'l',
...rest
}: PropsWithChildren<EuiFlyoutProps<T>>,
}: EuiFlyoutProps<T>,
ref:
| ((instance: ComponentPropsWithRef<T> | null) => void)
| MutableRefObject<ComponentPropsWithRef<T> | null>
| null
) => {
const Element = as || defaultElement;
/**
* Setting the initial state of pushed based on the `type` prop
* and if the current window size is large enough (larger than `pushMinBreakpoint`)
Expand Down Expand Up @@ -345,7 +339,6 @@ const EuiFlyout = forwardRef(
}

const flyoutContent = (
// @ts-expect-error JSX element without construct
<Element
{...(rest as ComponentPropsWithRef<T>)}
role={role}
Expand Down Expand Up @@ -399,8 +392,13 @@ const EuiFlyout = forwardRef(
</Fragment>
);
}
);

EuiFlyout.displayName = 'EuiFlyout';
// React.forwardRef interferes with the inferred element type
// Casting to ensure correct element prop type checking for `as`
// e.g., `href` is not on a `div`
) as <E extends React.ElementType = typeof defaultElement>(
props: EuiFlyoutProps<E>
) => JSX.Element;
// Recast to allow `displayName`
(EuiFlyout as FunctionComponent).displayName = 'EuiFlyout';

export { EuiFlyout };