Skip to content

Commit

Permalink
feat: add safe prop to links which allows easy bypassing of the `re…
Browse files Browse the repository at this point in the history
…l="noopener noreferrer"` which is now default
  • Loading branch information
maxholman committed Jan 17, 2023
1 parent b299ef8 commit 9dadf37
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 6 deletions.
19 changes: 15 additions & 4 deletions lib/buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { Box, BoxBasedComponentProps } from './core.js';
import type { Align } from './layout.css.js';
import { Inline } from './layout.js';
import { differentOriginLinkProps } from './links.js';
import { Tone, toneVariants } from './tone.css.js';
import type { Merge } from './types.js';

Expand All @@ -33,7 +34,9 @@ export type ButtonProps = PropsWithChildren<

export type ButtonLinkProps = Merge<
BoxBasedComponentProps<'a'>,
ButtonCommonProps
ButtonCommonProps & {
safe?: boolean;
}
>;

export type ButtonIconProps = Merge<
Expand All @@ -46,7 +49,7 @@ export type ButtonIconProps = Merge<
>;

const ButtonInternal: FC<
Merge<BoxBasedComponentProps<'button' | 'a' | 'span'>, ButtonCommonProps>
Merge<BoxBasedComponentProps<'button' | 'a'>, ButtonCommonProps>
> = ({
component = 'button',
variant = 'standard',
Expand Down Expand Up @@ -95,8 +98,16 @@ export const Button: FC<
Merge<BoxBasedComponentProps<'button'>, ButtonProps>
> = (props) => <ButtonInternal {...props} />;

export const ButtonLink: FC<ButtonLinkProps> = (props) => (
<ButtonInternal component={'href' in props ? 'a' : 'span'} {...props} />
export const ButtonLink: FC<ButtonLinkProps> = ({
component = 'a',
safe = true,
...props
}) => (
<ButtonInternal
component={component}
{...(safe && props.href && differentOriginLinkProps(props.href))}
{...props}
/>
);

export const ButtonIcon: FC<
Expand Down
4 changes: 2 additions & 2 deletions lib/forms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
ReactNode,
SelectHTMLAttributes,
TextareaHTMLAttributes,
useId,
} from 'react';
import { useStringLikeDetector } from './context.js';
import {
Expand All @@ -30,6 +29,7 @@ import {
formInputSelectWrapperSingle,
inputLabelStyle,
} from './forms.css.js';
import { useIdWithDefault } from './hooks/use-id-with-default.js';
import { Block, BlockProps, Inline } from './layout.js';
import type { Tone } from './tone.css.js';
import type { Merge } from './types.js';
Expand All @@ -45,7 +45,7 @@ type CommonFormInputProps = {
'radio' | 'checkbox'
>;
className?: ClassValue;
label: ReactNode;
label?: ReactNode;
description?: ReactNode;
secondaryLabel?: ReactNode;
tertiaryLabel?: ReactNode;
Expand Down
11 changes: 11 additions & 0 deletions lib/links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,28 @@ export type TextLinkProps = PropsWithChildren<
Merge<BoxBasedComponentProps<'a'>, TextLinkCommonProps>
>;

export function differentOriginLinkProps(href: string) {
if (typeof window !== 'undefined') {
const testUrl = new URL(href, window.location.origin);
if (testUrl.origin !== window.location.origin) {
return { target: '_blank', rel: 'noopener noreferrer' };
}
}
return null;
}

export const TextLink: FC<TextLinkProps> = ({
component = 'a',
children,
className,
weight = 'standard',
safe = true,
...props
}) => (
<Box
component={component}
className={[linkStyleVariant[weight], className]}
{...(safe && props.href && differentOriginLinkProps(props.href))}
{...props}
>
{children}
Expand Down

0 comments on commit 9dadf37

Please sign in to comment.