Update Link render prop mechanism
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -33,7 +33,7 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
href: 'https://canon.backstage.io',
|
||||
to: 'https://canon.backstage.io',
|
||||
children: 'Sign up for Backstage',
|
||||
},
|
||||
};
|
||||
@@ -66,6 +66,7 @@ export const AllWeights: Story = {
|
||||
|
||||
export const Responsive: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
variant: {
|
||||
xs: 'label',
|
||||
md: 'body',
|
||||
|
||||
@@ -14,45 +14,59 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { forwardRef } from 'react';
|
||||
import React, { forwardRef, memo, ComponentType } from 'react';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import type { LinkProps } from './types';
|
||||
import type { LinkProps, LinkRenderProps } from './types';
|
||||
|
||||
/** @public */
|
||||
export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
const {
|
||||
children,
|
||||
variant = 'body',
|
||||
weight = 'regular',
|
||||
style,
|
||||
className,
|
||||
render,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const responsiveWeight = useResponsiveValue(weight);
|
||||
|
||||
const linkProps = {
|
||||
ref,
|
||||
className: clsx(
|
||||
'canon-Link',
|
||||
responsiveVariant && `canon-Link--variant-${responsiveVariant}`,
|
||||
responsiveWeight && `canon-Link--weight-${responsiveWeight}`,
|
||||
export const Link = memo(
|
||||
forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
const {
|
||||
children,
|
||||
variant = 'body',
|
||||
weight = 'regular',
|
||||
style,
|
||||
className,
|
||||
),
|
||||
style,
|
||||
children,
|
||||
...restProps,
|
||||
};
|
||||
render,
|
||||
to,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
if (render) {
|
||||
return render(linkProps);
|
||||
}
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const responsiveWeight = useResponsiveValue(weight);
|
||||
|
||||
return <a {...linkProps} />;
|
||||
});
|
||||
const linkProps: LinkRenderProps = {
|
||||
className: clsx(
|
||||
'canon-Link',
|
||||
responsiveVariant && `canon-Link--variant-${responsiveVariant}`,
|
||||
responsiveWeight && `canon-Link--weight-${responsiveWeight}`,
|
||||
className,
|
||||
),
|
||||
style,
|
||||
children,
|
||||
to,
|
||||
...restProps,
|
||||
};
|
||||
|
||||
if (render) {
|
||||
// If render is a component type, wrap it in memo to prevent unnecessary re-renders
|
||||
if (typeof render === 'function' && !render.length) {
|
||||
const MemoizedComponent = memo(
|
||||
render as ComponentType<LinkRenderProps>,
|
||||
);
|
||||
return <MemoizedComponent {...linkProps} />;
|
||||
}
|
||||
// If it's a render function, call it directly
|
||||
const RenderComponent = render as (
|
||||
props: LinkRenderProps,
|
||||
) => React.ReactNode;
|
||||
return <RenderComponent {...linkProps} />;
|
||||
}
|
||||
|
||||
return <a ref={ref} href={to} {...linkProps} />;
|
||||
}),
|
||||
);
|
||||
|
||||
Link.displayName = 'Link';
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import type { CSSProperties, ReactNode, ComponentType } from 'react';
|
||||
import type { Breakpoint } from '../../types';
|
||||
|
||||
/** @public */
|
||||
export interface LinkProps
|
||||
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'to'> {
|
||||
children: ReactNode;
|
||||
to: string;
|
||||
variant?:
|
||||
| 'subtitle'
|
||||
| 'body'
|
||||
@@ -30,5 +31,10 @@ export interface LinkProps
|
||||
weight?: 'regular' | 'bold' | Partial<Record<Breakpoint, 'regular' | 'bold'>>;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
render?: (props: Omit<LinkProps, 'render'>) => ReactNode;
|
||||
render?:
|
||||
| ((props: Omit<LinkProps, 'render'>) => ReactNode)
|
||||
| ComponentType<Omit<LinkProps, 'render'>>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type LinkRenderProps = Omit<LinkProps, 'render'>;
|
||||
|
||||
@@ -42,6 +42,7 @@ export * from './components/Field';
|
||||
export * from './components/Tooltip';
|
||||
export * from './components/Menu';
|
||||
export * from './components/ScrollArea';
|
||||
export * from './components/Link';
|
||||
|
||||
// Types
|
||||
export * from './types';
|
||||
|
||||
Reference in New Issue
Block a user