From 20b6c6e401c626ef2ec39e251e9acf13a1bf9a94 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sun, 3 Sep 2023 01:03:34 +0800 Subject: [PATCH] Update LinkButton types Enable more type-safe approach to component and href props. --- .../react/src/components/LinkButton/index.tsx | 149 +++++++++++------- 1 file changed, 94 insertions(+), 55 deletions(-) diff --git a/categories/web/navigation/react/src/components/LinkButton/index.tsx b/categories/web/navigation/react/src/components/LinkButton/index.tsx index fdac0c7..11ef60c 100644 --- a/categories/web/navigation/react/src/components/LinkButton/index.tsx +++ b/categories/web/navigation/react/src/components/LinkButton/index.tsx @@ -7,46 +7,39 @@ import { Button } from '@tesseract-design/web-base'; */ export type LinkButtonDerivedElement = HTMLAnchorElement; -/** - * Props of the {@link LinkButton} component. - */ -export interface LinkButtonProps extends Omit, 'href' | 'size'> { - /** - * Should the component occupy the whole width of its parent? - */ - block?: boolean; - /** - * Variant of the component. - */ - variant?: Button.Variant; - /** - * Complementary content of the component. - */ - subtext?: React.ReactNode; - /** - * Short complementary content displayed at the edge of the component. - */ - badge?: React.ReactNode; - /** - * Is this component part of a menu? - */ - menuItem?: boolean; - /** - * Size of the component. - */ - size?: Button.Size; - /** - * Should the component's content use minimal space? - */ - compact?: boolean; - /** - * Component to use in rendering. - */ - component?: React.ElementType; - /** - * Is the component unable to receive activation? - */ - disabled?: boolean; +interface LinkButtonCommonProps extends Omit, 'href' | 'size'> { + /** + * Should the component occupy the whole width of its parent? + */ + block?: boolean; + /** + * Variant of the component. + */ + variant?: Button.Variant; + /** + * Complementary content of the component. + */ + subtext?: React.ReactNode; + /** + * Short complementary content displayed at the edge of the component. + */ + badge?: React.ReactNode; + /** + * Is this component part of a menu? + */ + menuItem?: boolean; + /** + * Size of the component. + */ + size?: Button.Size; + /** + * Should the component's content use minimal space? + */ + compact?: boolean; + /** + * Is the component unable to receive activation? + */ + disabled?: boolean; /** * Graphical representation of the component. */ @@ -55,12 +48,36 @@ export interface LinkButtonProps extends Omit, 'href'> { + component: 'a'; +} + +interface LinkButtonComponentType { + (props: { href?: string }): React.ReactNode; +} + +interface LinkButtonFCProps< + C extends LinkButtonComponentType = LinkButtonComponentType +> { + component: C; + href: C extends (props: { href?: infer Href }) => React.ReactNode ? Href : never; +} + +type LinkButtonAllProps< + T extends LinkButtonComponentType = LinkButtonComponentType +> = + LinkButtonAnchorProps | LinkButtonFCProps; + +/** + * Props of the {@link LinkButton} component. + */ +export type LinkButtonProps< + T extends LinkButtonComponentType = LinkButtonComponentType +> = + LinkButtonCommonProps & LinkButtonAllProps; + /** * Component for performing a navigation action. */ @@ -75,7 +92,7 @@ export const LinkButton = React.forwardRef { - const Component = disabled ? 'button' : EnabledComponent; + const Component = (disabled ? 'button' : EnabledComponent) as 'a'; + const extraProps = { + disabled: disabled || undefined, + }; + return ( { +// return null; +// }; +// +// const a = ( +// +// );