From 268be6815f9a065eef91f9f20eea5d0c336939a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Mon, 13 Jun 2022 00:00:09 +0200 Subject: [PATCH 1/4] ExternalLink: Convert component to TypeScript --- .../components/src/external-link/README.md | 12 ++++++ .../src/external-link/{index.js => index.tsx} | 32 +++++++++++++--- .../src/external-link/stories/index.js | 23 ------------ .../src/external-link/stories/index.tsx | 37 +++++++++++++++++++ ...link-styles.js => external-link-styles.ts} | 0 .../components/src/external-link/types.ts | 11 ++++++ packages/components/tsconfig.json | 1 + 7 files changed, 87 insertions(+), 29 deletions(-) rename packages/components/src/external-link/{index.js => index.tsx} (57%) delete mode 100644 packages/components/src/external-link/stories/index.js create mode 100644 packages/components/src/external-link/stories/index.tsx rename packages/components/src/external-link/styles/{external-link-styles.js => external-link-styles.ts} (100%) create mode 100644 packages/components/src/external-link/types.ts diff --git a/packages/components/src/external-link/README.md b/packages/components/src/external-link/README.md index 73fe8b5c3fbdd0..c1ddad9767b495 100644 --- a/packages/components/src/external-link/README.md +++ b/packages/components/src/external-link/README.md @@ -1,5 +1,7 @@ # ExternalLink +Link to an external resource. + ## Usage ```jsx @@ -9,3 +11,13 @@ const MyExternalLink = () => ( WordPress.org ); ``` + +## Props + +The component accepts the following props. Any other props will be passed through to the `a`. + +### `children`: `ReactNode` + +The content to be displayed within the link. + +- Required: No diff --git a/packages/components/src/external-link/index.js b/packages/components/src/external-link/index.tsx similarity index 57% rename from packages/components/src/external-link/index.js rename to packages/components/src/external-link/index.tsx index 45c2e403f14c4e..44d006a676e267 100644 --- a/packages/components/src/external-link/index.js +++ b/packages/components/src/external-link/index.tsx @@ -3,6 +3,7 @@ */ import classnames from 'classnames'; import { compact, uniq } from 'lodash'; +import type { ForwardedRef } from 'react'; /** * WordPress dependencies @@ -16,12 +17,18 @@ import { external } from '@wordpress/icons'; */ import { VisuallyHidden } from '../visually-hidden'; import { StyledIcon } from './styles/external-link-styles'; +import type { ExternalLinkProps } from './types'; +import type { WordPressComponentProps } from '../ui/context'; -export function ExternalLink( - { href, children, className, rel = '', ...additionalProps }, - ref +function UnforwardedExternalLink( + props: Omit< + WordPressComponentProps< ExternalLinkProps, 'a', false >, + 'target' + >, + ref: ForwardedRef< HTMLAnchorElement > ) { - rel = uniq( + const { href, children, className, rel = '', ...additionalProps } = props; + const optimizedRel = uniq( compact( [ ...rel.split( ' ' ), 'external', 'noreferrer', 'noopener' ] ) ).join( ' ' ); const classes = classnames( 'components-external-link', className ); @@ -32,7 +39,7 @@ export function ExternalLink( className={ classes } href={ href } target="_blank" - rel={ rel } + rel={ optimizedRel } ref={ ref } > { children } @@ -51,4 +58,17 @@ export function ExternalLink( ); } -export default forwardRef( ExternalLink ); +/** + * Link to an external resource. + * + * ```jsx + * import { ExternalLink } from '@wordpress/components'; + * + * const MyExternalLink = () => ( + * WordPress.org + * ); + * ``` + */ +export const ExternalLink = forwardRef( UnforwardedExternalLink ); + +export default ExternalLink; diff --git a/packages/components/src/external-link/stories/index.js b/packages/components/src/external-link/stories/index.js deleted file mode 100644 index 5f69a3f1d9cc91..00000000000000 --- a/packages/components/src/external-link/stories/index.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * External dependencies - */ -import { text } from '@storybook/addon-knobs'; -/** - * Internal dependencies - */ -import ExternalLink from '../'; - -export default { - title: 'Components/ExternalLink', - component: ExternalLink, - parameters: { - knobs: { disable: false }, - }, -}; - -export const _default = () => { - const title = text( 'children', 'WordPress' ); - const href = text( 'href', 'https://wordpress.org' ); - - return { title }; -}; diff --git a/packages/components/src/external-link/stories/index.tsx b/packages/components/src/external-link/stories/index.tsx new file mode 100644 index 00000000000000..0bc8567b82508d --- /dev/null +++ b/packages/components/src/external-link/stories/index.tsx @@ -0,0 +1,37 @@ +/** + * External dependencies + */ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; + +/** + * Internal dependencies + */ +import ExternalLink from '..'; + +const meta: ComponentMeta< typeof ExternalLink > = { + component: ExternalLink, + title: 'Components/ExternalLink', + argTypes: { + children: { control: { type: 'text' } }, + }, + parameters: { + controls: { + expanded: true, + exclude: [ 'heading' ], + }, + docs: { source: { state: 'open' } }, + }, +}; +export default meta; + +const Template: ComponentStory< typeof ExternalLink > = ( { ...args } ) => { + return ; +}; + +export const Default: ComponentStory< typeof ExternalLink > = Template.bind( + {} +); +Default.args = { + children: 'WordPress', + href: 'https://wordpress.org', +}; diff --git a/packages/components/src/external-link/styles/external-link-styles.js b/packages/components/src/external-link/styles/external-link-styles.ts similarity index 100% rename from packages/components/src/external-link/styles/external-link-styles.js rename to packages/components/src/external-link/styles/external-link-styles.ts diff --git a/packages/components/src/external-link/types.ts b/packages/components/src/external-link/types.ts new file mode 100644 index 00000000000000..cd84c02d7d3025 --- /dev/null +++ b/packages/components/src/external-link/types.ts @@ -0,0 +1,11 @@ +/** + * External dependencies + */ +import type { ReactNode } from 'react'; + +export type ExternalLinkProps = { + /** + * The content to be displayed within the link. + */ + children?: ReactNode; +}; diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 4ed0fba2b54c98..060575f52426d7 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -54,6 +54,7 @@ "src/dropdown/**/*", "src/dropdown-menu/**/*", "src/elevation/**/*", + "src/external-link/**/*", "src/flex/**/*", "src/form-group/**/*", "src/form-token-field/**/*", From cfa8b3b0ead59c584eb6ed59fbe9dce6c3da2dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Mon, 13 Jun 2022 00:03:40 +0200 Subject: [PATCH 2/4] Update CHANGELOG.md --- packages/components/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 021bbbc869b408..edb115628e31fc 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -22,7 +22,7 @@ - `CustomGradientBar` updated to satisfy `react/exhuastive-deps` eslint rule ([#41463](https://github.com/WordPress/gutenberg/pull/41463)) - `TreeSelect`: Convert to TypeScript ([#41536](https://github.com/WordPress/gutenberg/pull/41536)). - `FontSizePicker`: updated to satisfy `react/exhuastive-deps` eslint rule ([#41600](https://github.com/WordPress/gutenberg/pull/41600)). - +- `ExternalLink`: Convert to TypeScript ([#41681](https://github.com/WordPress/gutenberg/pull/41681)). ## 19.12.0 (2022-06-01) From 53324de0a7d6934c8ad485d1f5b2de83fec56d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Mon, 13 Jun 2022 21:12:51 +0200 Subject: [PATCH 3/4] Remove exclude from story --- packages/components/src/external-link/stories/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/external-link/stories/index.tsx b/packages/components/src/external-link/stories/index.tsx index 0bc8567b82508d..f782d962f3740f 100644 --- a/packages/components/src/external-link/stories/index.tsx +++ b/packages/components/src/external-link/stories/index.tsx @@ -17,7 +17,6 @@ const meta: ComponentMeta< typeof ExternalLink > = { parameters: { controls: { expanded: true, - exclude: [ 'heading' ], }, docs: { source: { state: 'open' } }, }, From c6d045eba3e43826af880e410d02bdabb5431dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Tue, 14 Jun 2022 14:13:30 +0200 Subject: [PATCH 4/4] Mark children and href as required --- packages/components/src/external-link/README.md | 8 +++++++- packages/components/src/external-link/types.ts | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/components/src/external-link/README.md b/packages/components/src/external-link/README.md index c1ddad9767b495..c0e5621154cc29 100644 --- a/packages/components/src/external-link/README.md +++ b/packages/components/src/external-link/README.md @@ -20,4 +20,10 @@ The component accepts the following props. Any other props will be passed throug The content to be displayed within the link. -- Required: No +- Required: Yes + +### `href`: `string` + +The URL of the external resource. + +- Required: Yes diff --git a/packages/components/src/external-link/types.ts b/packages/components/src/external-link/types.ts index cd84c02d7d3025..a2b5cfb8324ced 100644 --- a/packages/components/src/external-link/types.ts +++ b/packages/components/src/external-link/types.ts @@ -7,5 +7,9 @@ export type ExternalLinkProps = { /** * The content to be displayed within the link. */ - children?: ReactNode; + children: ReactNode; + /** + * The URL of the external resource. + */ + href: string; };