Skip to content

Commit efad82b

Browse files
authored
[EuiFlyout] Refactor polymorphic types (#4940)
* refactor polymorphic types * CL
1 parent ef0ec12 commit efad82b

File tree

3 files changed

+33
-30
lines changed

3 files changed

+33
-30
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## [`master`](https://github.com/elastic/eui/tree/master)
22

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

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

src/components/common.ts

+5
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ export type PropsOf<C> = C extends SFC<infer SFCProps>
5555
? ComponentProps
5656
: never;
5757

58+
// Returns the props of a given HTML element
59+
export type PropsOfElement<
60+
C extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
61+
> = JSX.LibraryManagedAttributes<C, React.ComponentProps<C>>;
62+
5863
// Utility methods for ApplyClassComponentDefaults
5964
type ExtractDefaultProps<T> = T extends { defaultProps: infer D } ? D : never;
6065
type ExtractProps<

src/components/flyout/flyout.tsx

+27-29
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import React, {
1212
forwardRef,
1313
CSSProperties,
1414
Fragment,
15-
ComponentType,
15+
FunctionComponent,
1616
ComponentPropsWithRef,
17-
PropsWithChildren,
1817
MutableRefObject,
1918
} from 'react';
2019
import classnames from 'classnames';
@@ -28,7 +27,7 @@ import {
2827
throttle,
2928
} from '../../services';
3029

31-
import { CommonProps, keysOf } from '../common';
30+
import { CommonProps, keysOf, PropsOfElement } from '../common';
3231
import { EuiFocusTrap } from '../focus_trap';
3332
import { EuiOverlayMask, EuiOverlayMaskProps } from '../overlay_mask';
3433
import { EuiButtonIcon, EuiButtonIconPropsForButton } from '../button';
@@ -153,32 +152,26 @@ type _EuiFlyoutProps = {
153152
style?: React.CSSProperties;
154153
};
155154

156-
// Using ReactHTML rather than JSX.IntrinsicElements here because it does not include
157-
// SVG element types which cause errors because they do not have all the attributes needed.
158-
type ComponentTypes =
159-
| 'div'
160-
| 'span'
161-
| 'nav'
162-
| 'aside'
163-
| 'section'
164-
| 'article'
165-
| 'header'
166-
| ComponentType;
167-
168-
export type EuiFlyoutProps<T extends ComponentTypes = 'div'> = CommonProps &
169-
ComponentPropsWithRef<T> & {
170-
/**
171-
* Sets the HTML element for `EuiFlyout`
172-
*/
173-
as?: T;
174-
} & _EuiFlyoutProps;
155+
const defaultElement = 'div';
156+
157+
type Props<T extends React.ElementType> = CommonProps & {
158+
/**
159+
* Sets the HTML element for `EuiFlyout`
160+
*/
161+
as?: T;
162+
} & _EuiFlyoutProps &
163+
Omit<PropsOfElement<T>, keyof _EuiFlyoutProps>;
164+
165+
export type EuiFlyoutProps<
166+
T extends React.ElementType = typeof defaultElement
167+
> = Props<T> & Omit<ComponentPropsWithRef<T>, keyof Props<T>>;
175168

176169
const EuiFlyout = forwardRef(
177-
<T extends ComponentTypes>(
170+
<T extends React.ElementType = typeof defaultElement>(
178171
{
179172
className,
180173
children,
181-
as: Element = 'div' as T,
174+
as,
182175
hideCloseButton = false,
183176
closeButtonProps,
184177
closeButtonAriaLabel,
@@ -196,12 +189,13 @@ const EuiFlyout = forwardRef(
196189
role = 'dialog',
197190
pushMinBreakpoint = 'l',
198191
...rest
199-
}: PropsWithChildren<EuiFlyoutProps<T>>,
192+
}: EuiFlyoutProps<T>,
200193
ref:
201194
| ((instance: ComponentPropsWithRef<T> | null) => void)
202195
| MutableRefObject<ComponentPropsWithRef<T> | null>
203196
| null
204197
) => {
198+
const Element = as || defaultElement;
205199
/**
206200
* Setting the initial state of pushed based on the `type` prop
207201
* and if the current window size is large enough (larger than `pushMinBreakpoint`)
@@ -345,7 +339,6 @@ const EuiFlyout = forwardRef(
345339
}
346340

347341
const flyoutContent = (
348-
// @ts-expect-error JSX element without construct
349342
<Element
350343
{...(rest as ComponentPropsWithRef<T>)}
351344
role={role}
@@ -399,8 +392,13 @@ const EuiFlyout = forwardRef(
399392
</Fragment>
400393
);
401394
}
402-
);
403-
404-
EuiFlyout.displayName = 'EuiFlyout';
395+
// React.forwardRef interferes with the inferred element type
396+
// Casting to ensure correct element prop type checking for `as`
397+
// e.g., `href` is not on a `div`
398+
) as <E extends React.ElementType = typeof defaultElement>(
399+
props: EuiFlyoutProps<E>
400+
) => JSX.Element;
401+
// Recast to allow `displayName`
402+
(EuiFlyout as FunctionComponent).displayName = 'EuiFlyout';
405403

406404
export { EuiFlyout };

0 commit comments

Comments
 (0)