refactor: update text and link components to be polymorphic (#171)
This commit is contained in:
@@ -7,31 +7,28 @@ import React from 'react';
|
||||
|
||||
import styles from './Link.module.scss';
|
||||
|
||||
type Props = Omit<TextProps, 'span'> & {
|
||||
url?: string;
|
||||
type Props = TextProps<'a'> & {
|
||||
href?: string;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A reusable Text component with props that build on top of the design system for the extension
|
||||
*/
|
||||
export default function Link(props: PropsWithChildren<Props>): JSX.Element {
|
||||
let passedProps = {
|
||||
...props,
|
||||
};
|
||||
const { url } = props;
|
||||
let { className, href, ...passedProps } = props;
|
||||
|
||||
if (url && !props.onClick) {
|
||||
passedProps.onClick = () => background.openNewTab({ url });
|
||||
if (href && !props.onClick) {
|
||||
passedProps.onClick = () => background.openNewTab({ url: href });
|
||||
}
|
||||
const isDisabled = props.disabled || (!url && !props.onClick);
|
||||
const isDisabled = props.disabled || (!href && !props.onClick);
|
||||
|
||||
return (
|
||||
<Text
|
||||
color='bluebonnet'
|
||||
{...passedProps}
|
||||
as='span'
|
||||
as='a'
|
||||
tabIndex={isDisabled ? -1 : 0}
|
||||
className={clsx(
|
||||
styles.link,
|
||||
{
|
||||
|
||||
@@ -1,34 +1,49 @@
|
||||
import type { PropsOf, ReactTag } from '@headlessui/react/dist/types';
|
||||
import clsx from 'clsx';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import type { ElementType, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import styles from './Text.module.scss';
|
||||
|
||||
/**
|
||||
* Props for the Text component.
|
||||
*/
|
||||
export type TextProps = {
|
||||
variant?: Variant;
|
||||
} & (
|
||||
| (React.HTMLAttributes<HTMLSpanElement> & { as?: 'span' })
|
||||
| (React.HTMLAttributes<HTMLDivElement> & { as: 'div' })
|
||||
);
|
||||
type PropsWeControl = 'as' | 'children';
|
||||
type CleanProps<TTag extends ReactTag, TOmitableProps extends PropertyKey = never> = Omit<
|
||||
PropsOf<TTag>,
|
||||
TOmitableProps | PropsWeControl
|
||||
>;
|
||||
type OurProps<TTag extends ReactTag> = {
|
||||
as?: TTag;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
type AsProps<TTag extends ReactTag, TOverrides = {}> = CleanProps<TTag, keyof TOverrides> & OurProps<TTag> & TOverrides;
|
||||
|
||||
const variants = ['mini', 'small', 'p', 'h4', 'h3-course', 'h3', 'h2-course', 'h2', 'h1-course', 'h1'] as const;
|
||||
|
||||
type Variant = (typeof variants)[number];
|
||||
|
||||
/**
|
||||
* Props for the Text component.
|
||||
*/
|
||||
export type TextProps<TTag extends ElementType = 'span'> = PropsOf<TTag>['className'] extends string
|
||||
? AsProps<
|
||||
TTag,
|
||||
{
|
||||
variant?: Variant;
|
||||
}
|
||||
>
|
||||
: never;
|
||||
|
||||
/**
|
||||
* A reusable Text component with props that build on top of the design system for the extension
|
||||
*/
|
||||
export default function Text({ variant, as, className, ...props }: PropsWithChildren<TextProps>): JSX.Element {
|
||||
const mergedClassName = clsx(styles.text, styles[variant], className);
|
||||
export default function Text<TTag extends ElementType = 'span'>({
|
||||
as,
|
||||
className,
|
||||
variant,
|
||||
...rest
|
||||
}: TextProps<TTag>): JSX.Element {
|
||||
const Comp = as || 'span';
|
||||
const mergedClassName = clsx(styles.text, styles[variant || 'p'], className);
|
||||
|
||||
if (as === 'div') return <div className={mergedClassName} {...props} />;
|
||||
|
||||
return (
|
||||
<span className={mergedClassName} {...props}>
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
return <Comp className={mergedClassName} {...rest} />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user