From bdce10a700950ab7c8e16e04aa5f4e49b35f88cb Mon Sep 17 00:00:00 2001 From: Andrew Holloway Date: Tue, 19 Mar 2024 15:59:13 -0500 Subject: [PATCH] feat(Link)!: introduce v2.0 component (#1890) - add stories and styles to match new design - update snapshots - also add in the nested V2 folder in storybook, and export --- src/components/Link/Link-v2.module.css | 93 +++++++++++++++++++++++++ src/components/Link/Link-v2.stories.tsx | 88 +++++++++++++++++++++++ src/components/Link/Link-v2.tsx | 92 ++++++++++++++++++++++++ src/components/Link/index.ts | 1 + 4 files changed, 274 insertions(+) create mode 100644 src/components/Link/Link-v2.module.css create mode 100644 src/components/Link/Link-v2.stories.tsx create mode 100644 src/components/Link/Link-v2.tsx diff --git a/src/components/Link/Link-v2.module.css b/src/components/Link/Link-v2.module.css new file mode 100644 index 000000000..5adeba7d3 --- /dev/null +++ b/src/components/Link/Link-v2.module.css @@ -0,0 +1,93 @@ +@import '../../design-tokens/mixins.css'; + +/*------------------------------------*\ + # LINK +\*------------------------------------*/ + +.link { + color: var(--eds-theme-color-text-utility-neutral-primary); + display: inline; + + /* TODO-AH: verify the way to sync type tokens and one-off treatments */ + font-weight: 500; + text-decoration-line: underline; +} + +/** + * Sub-components + */ +.link__icon { + padding-left: 0.25rem; + + /* Sub-component spacing */ + &.link--size-xl, + &.link--size-lg { padding-left: 0.5rem; } + + &.link--size-md, + &.link--size-sm, + &.link--size-xs { padding-left: 0.25rem; } +} + +/** + * Contexts + */ +.link--context-standalone { + display: block; + + /** + * Sizes - using the presets for type ramp matching body-* + */ + &.link--size-xl { + font: var(--eds-theme-typography-body-xl); + } + + &.link--size-lg { + font: var(--eds-theme-typography-body-lg); + } + + &.link--size-md { + font: var(--eds-theme-typography-body-md); + } + + &.link--size-sm { + font: var(--eds-theme-typography-body-sm); + } + + &.link--size-xs { + font: var(--eds-theme-typography-body-xs); + } +} + +/** + * Emphasis + */ +.link--emphasis-high { + color: var(--eds-theme-color-text-utility-interactive-secondary); +} + +.link--emphasis-low { + color: var(--eds-theme-color-text-utility-neutral-primary); + text-decoration: none; +} + + +/** + * States + */ + +.link:hover { + color: var(--eds-theme-color-text-utility-interactive-secondary-hover); +} + +.link:active { + color: var(--eds-theme-color-text-utility-interactive-secondary-active); +} + +.link:visited { + color: var(--eds-theme-color-text-utility-interactive-visited); +} + +.link:focus-visible { + outline: 0.125rem solid var(--eds-theme-color-border-utility-focus); + outline-offset: 0.125rem; +} \ No newline at end of file diff --git a/src/components/Link/Link-v2.stories.tsx b/src/components/Link/Link-v2.stories.tsx new file mode 100644 index 000000000..b71b2becd --- /dev/null +++ b/src/components/Link/Link-v2.stories.tsx @@ -0,0 +1,88 @@ +import type { StoryObj, Meta } from '@storybook/react'; +import React from 'react'; +import { Link, type LinkProps } from './Link-v2'; + +export default { + title: 'Components/V2/Link', + component: Link, + parameters: { + badges: ['intro-1.0', 'current-2.0'], + }, + args: { + children: 'Link', + size: 'lg', + href: 'https://go.czi.team/eds', + // stop link from navigating to another page so we can click the link for testing + onClick: (event: any) => event.preventDefault(), + }, +} as Meta; + +type Args = React.ComponentProps; + +export const Default: StoryObj = {}; + +export const LinkWithChevron: StoryObj = { + args: { + children: 'Default', + context: 'standalone', + icon: 'chevron-right', + }, +}; + +export const LinkWithOpenIcon: StoryObj = { + args: { + children: 'Default', + context: 'standalone', + icon: 'open-in-new', + }, +}; + +export const Emphasis: StoryObj = { + args: { + size: 'md', + context: 'standalone', + }, + render: (args) => { + return ( +
+ + Default Emphasis + + + High Emphasis + + + Low Emphasis + +
+ ); + }, +}; + +export const LinkInParagraphContext: StoryObj = { + render: ( + args: React.JSX.IntrinsicAttributes & + (LinkProps & React.RefAttributes), + ) => ( +
+ Lorem ipsum dolor sit amet,{' '} + + consectetur adipiscing elit + + . Morbi porta at ante quis molestie. Nam scelerisque id diam at iaculis. + Nullam sit amet iaculis erat. Nulla id tellus ante.{' '} + + Aliquam pellentesque ipsum sagittis, commodo neque at, ornare est. + Maecenas a malesuada sem, vitae euismod erat. Nullam molestie nunc non + dui dignissim fermentum. + {' '} + Aliquam id volutpat nulla, sed auctor orci. Fusce cursus leo nisi. Fusce + vehicula vitae nisl nec ultricies. Cras ut enim nec magna semper egestas. + Sed sed quam id nisl bibendum convallis. Proin suscipit, odio{' '} + + vel pulvinar + {' '} + euismod, risus eros ullamcorper lectus, non blandit nulla dui eget massa. +
+ ), +}; diff --git a/src/components/Link/Link-v2.tsx b/src/components/Link/Link-v2.tsx new file mode 100644 index 000000000..48c29a5e0 --- /dev/null +++ b/src/components/Link/Link-v2.tsx @@ -0,0 +1,92 @@ +import clsx from 'clsx'; +import React, { forwardRef } from 'react'; +import type { Size } from '../../util/variant-types'; +import type { IconName } from '../Icon'; +import Icon from '../Icon'; + +import styles from './Link-v2.module.css'; + +export type LinkProps = React.AnchorHTMLAttributes & { + // Component API + /** + * Component used to render the element. Meant to support interaction with framework navigation libraries. + * TODO-AH: support frameworks that may not use (or replace) `href` for some other prop + * + * **Default is `"a"`**. + */ + as: string | React.ElementType; + /** + * The link contents or label. + */ + children: string; + // Design API + /** + * Where `Link` sits alongside other text and content: + * + * * **inline** - Inline link inherits the text size established within the `

` paragraph they are embedded in. + * * **standalone** - Users can choose from the available sizes. + */ + context?: 'inline' | 'standalone'; + /** + * (trailing) icon to use with the link + */ + icon?: Extract; + /** + * Extra or lowered colors added to a link + */ + emphasis?: 'default' | 'high' | 'low'; + + /** + * Link size inherits from the surrounding text. + */ + size?: Extract; +}; + +/** + * `import {Link} from "@chanzuckerberg/eds";` + * + * Component for making styled anchor tags. Links allow users to navigate within or between a web page(s) or app(s). + * + */ +export const Link = forwardRef( + ( + { + as: Component = 'a', + children, + className, + context, + emphasis = 'default', + icon, + size = 'md', + ...other + }, + ref, + ) => { + const componentClassName = clsx( + className, + styles['link'], + context && styles[`link--context-${context}`], + emphasis && styles[`link--emphasis-${emphasis}`], + icon && styles['link--has-right-icon'], + size && styles[`link--size-${size}`], + ); + + const iconSize = size && (['xl', 'lg'].includes(size) ? '1.5rem' : '1rem'); + + return ( + + {children} + {icon && context === 'standalone' && ( + + )} + + ); + }, +); + +Link.displayName = 'Link'; diff --git a/src/components/Link/index.ts b/src/components/Link/index.ts index 9ca843623..478ceccda 100644 --- a/src/components/Link/index.ts +++ b/src/components/Link/index.ts @@ -1,2 +1,3 @@ export { Link as default } from './Link'; export type { LinkProps } from './Link'; +export { Link as LinkV2 } from './Link-v2';