Skip to content

Commit

Permalink
feat!: Refactor External Hyperlink to use new styling utilities (#3101)
Browse files Browse the repository at this point in the history
Fixes: #2955

[category:Components]

Release Note:
We've updated `ExternalHyperlink` to use our new styling utilities and tokens.

### BREAKING CHANGES
`iconLabel` is now a *required* prop. We've removed the default `aria-label` of `Opens link in new window` to better support internationalization. You must provide a value to `iconLabel`.

Co-authored-by: manuel.carrera <[email protected]>
  • Loading branch information
mannycarrera4 and manuel.carrera authored Jan 24, 2025
1 parent b5251e8 commit 8690580
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 51 deletions.
2 changes: 1 addition & 1 deletion modules/docs/lib/StylePropsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const StylePropsTable = ({styleProps = []}: StylePropsTableProps) => {
const mdnUrl = `https://developer.mozilla.org/en-US/docs/Web/CSS/${formattedName}`;
return (
<Box display="inline-block" marginInlineEnd="xxxs">
<ExternalHyperlink href={mdnUrl} key={i}>
<ExternalHyperlink href={mdnUrl} key={i} iconLabel="Open link in new window">
{formattedName}
</ExternalHyperlink>
</Box>
Expand Down
4 changes: 3 additions & 1 deletion modules/docs/lib/widgets/external.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {registerWidget} from '../Value';

registerWidget<ExternalSymbolValue>('external', ({value}) => (
<>
<ExternalHyperlink href={value.url}>{value.name}</ExternalHyperlink>
<ExternalHyperlink href={value.url} iconLabel="Open link in new window">
{value.name}
</ExternalHyperlink>
{renderTypeParameters(value.typeParameters)}
</>
));
32 changes: 30 additions & 2 deletions modules/docs/mdx/13.0-UPGRADE-GUIDE.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ any questions.
- [Instructions](#instructions)
- [Component Updates](#component-updates)
- [Styling API and CSS Tokens](#styling-api-and-css-tokens)
- [External Hyperlink](#external-hyperlink)
- [Troubleshooting](#troubleshooting)
- [Glossary](#glossary)
- [Main](#main)
Expand Down Expand Up @@ -87,18 +88,45 @@ yarn remove @workday/canvas-kit-codemod
> after executing the codemod, as its resulting formatting (spacing, quotes, etc.) may not match
> your project conventions.
## Component Updates

### Styling API and CSS Tokens

Some components have been refactored to use our new
**PRs:** [#3101](https://github.com/Workday/canvas-kit/pull/3101), [#3088](https://github.com/Workday/canvas-kit/pull/3088)

Several components have been refactored to use our
[Canvas Tokens](https://workday.github.io/canvas-tokens/?path=/docs/docs-getting-started--docs) and
[styling API](https://workday.github.io/canvas-kit/?path=/docs/styling-basics--create-modifiers#createstyles-api).
The React interface **has not changed**, but CSS variables are now used for dynamic properties.

> **Note:** These components also support our new `cs` prop for styling. Learn more about styling
> **Note:** These components also support our `cs` prop for styling. Learn more about styling
> with `cs` in our
> [documentation](https://workday.github.io/canvas-kit/?path=/docs/styling-basics--cs-prop).
The following components are affected:

- `ExternalHyperlink`
- `Skeleton`

## External Hyperlink

**PR:** [#3101](https://github.com/Workday/canvas-kit/pull/3101)

`iconLabel` is now a *required* prop. We've removed the default `aria-label` of `Opens link in new window` to better support internationalization. You must provide a value to `iconLabel`.

```tsx
//v12
<ExternalHyperlink href="https://workday.com">
External Hyperlink
</ExternalHyperlink>

//v13
<ExternalHyperlink href="https://workday.com" iconLabel='Open link in new window'>
External Hyperlink
</ExternalHyperlink>
```


## Troubleshooting

## Glossary
Expand Down
5 changes: 4 additions & 1 deletion modules/docs/mdx/welcomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export const WelcomePage = () => {
{' '}
This project provides a set of components for the Workday Canvas Design System that can be
used to implement user experiences consistent with{' '}
<ExternalHyperlink href="https://canvas.workdaydesign.com/">
<ExternalHyperlink
href="https://canvas.workdaydesign.com/"
iconLabel="Open docs in new window"
>
Workday Design Principles.
</ExternalHyperlink>
</Text>
Expand Down
69 changes: 37 additions & 32 deletions modules/react/button/lib/ExternalHyperlink.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
import React from 'react';
import {styled, createComponent, StyledType} from '@workday/canvas-kit-react/common';
import {createComponent} from '@workday/canvas-kit-react/common';
import {extLinkIcon} from '@workday/canvas-system-icons-web';
import {SystemIcon, systemIconStyles} from '@workday/canvas-kit-react/icon';
import {Hyperlink, HyperlinkProps} from './Hyperlink';
import {SystemIcon, systemIconStencil} from '@workday/canvas-kit-react/icon';
import {HyperlinkProps, hyperlinkStencil} from './Hyperlink';
import {calc, createStencil, px2rem, handleCsProp} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

export interface ExternalHyperlinkProps extends HyperlinkProps {
/**
* Informs a screen reader user the link will open in a new window. It is read after the link text.
* This value will need to be translated.
* @default 'Opens link in new window'
*/
iconLabel?: string;
iconLabel: string;
}

const iconStyles = {
...systemIconStyles({fill: 'currentColor', fillHover: 'currentColor'}),
};

const Anchor = styled(Hyperlink)<ExternalHyperlinkProps & StyledType>({
...iconStyles,
display: 'inline-flex',
flexDirection: 'row',
alignItems: 'center',
});

const iconSize = '1em';
const minIconSize = '16px';

const StyledSystemIcon = styled(SystemIcon)<StyledType>({
...iconStyles,
width: `calc(${iconSize} - 1px)`,
minWidth: `calc(${minIconSize} - 1px)`,
marginLeft: '2px',
export const externalHyperlinkStencil = createStencil({
extends: hyperlinkStencil,
base: {
display: 'inline-flex',
flexDirection: 'row',
alignItems: 'center',
'& [data-part="external-hyperlink-icon"]': {
[systemIconStencil.vars.color]: 'currentColor',
[systemIconStencil.vars.size]: '1em',
width: calc.subtract('1em', px2rem(1)),
minWidth: calc.subtract(system.space.x4, px2rem(1)),
marginInlineStart: calc.subtract(system.space.x1, px2rem(2)),
'& > svg': {
minWidth: system.space.x4,
minHeight: system.space.x4,
},
},
},
});

/**
Expand All @@ -41,18 +41,23 @@ const StyledSystemIcon = styled(SystemIcon)<StyledType>({
export const ExternalHyperlink = createComponent('a')({
displayName: 'ExternalHyperlink',
Component: (
{children, iconLabel = 'Opens link in new window', ...elemProps}: ExternalHyperlinkProps,
ref
{children, iconLabel, variant, ...elemProps}: ExternalHyperlinkProps,
ref,
Element
) => (
<Anchor ref={ref} target="_blank" rel="noreferrer" {...elemProps}>
<span>{children}</span>
<StyledSystemIcon
<Element
ref={ref}
target="_blank"
rel="noreferrer"
{...handleCsProp(elemProps, externalHyperlinkStencil({variant}))}
>
<span data-part="external-hyperlink-children">{children}</span>
<SystemIcon
icon={extLinkIcon}
role="img"
aria-label={iconLabel}
size={iconSize}
cs={{'& svg': {minWidth: minIconSize, minHeight: minIconSize}}}
data-part="external-hyperlink-icon"
/>
</Anchor>
</Element>
),
});
2 changes: 1 addition & 1 deletion modules/react/button/lib/Hyperlink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface HyperlinkProps extends CSProps {
children?: React.ReactNode;
}

const hyperlinkStencil = createStencil({
export const hyperlinkStencil = createStencil({
base: {
fontFamily: system.fontFamily.default,
textDecoration: 'underline',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ import React from 'react';
import {ExternalHyperlink} from '@workday/canvas-kit-react/button';

export const ExternalLink = () => (
<ExternalHyperlink href="https://workday.com">External Hyperlink</ExternalHyperlink>
<ExternalHyperlink href="https://workday.com" iconLabel="Opens link in new window">
External Hyperlink
</ExternalHyperlink>
);
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ const parentContainerStyles = createStyles({

export const ExternalLinkInverse = () => (
<Box cs={parentContainerStyles}>
<ExternalHyperlink href="https://workday.com" variant="inverse">
<ExternalHyperlink
href="https://workday.com"
variant="inverse"
iconLabel="Opens link in new window"
>
Hyperlink
</ExternalHyperlink>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@workday/canvas-kit-react/testing';
import {ExternalHyperlink} from '@workday/canvas-kit-react/button';
import {Container} from './utils';
import {Box, Flex} from '@workday/canvas-kit-react/layout';
import {Flex} from '@workday/canvas-kit-react/layout';
import {BodyText, Subtext} from '@workday/canvas-kit-react/text';

export default {
Expand Down Expand Up @@ -49,7 +49,11 @@ export const ExternalHyperlinkStates = {
{(props: any) => (
<Container blue={props.variant === 'inverse'}>
<Subtext as="span" size="large" variant={props.variant}>
Here's a <ExternalHyperlink {...props}>Link</ExternalHyperlink> to something
Here's a{' '}
<ExternalHyperlink {...props} iconLabel="Opens link in new window">
Link
</ExternalHyperlink>{' '}
to something
</Subtext>
</Container>
)}
Expand All @@ -58,31 +62,47 @@ export const ExternalHyperlinkStates = {
<Flex flexDirection="column" gap="xxs">
<h3>Typography</h3>
<Subtext size="large">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</Subtext>
<BodyText size="small">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</BodyText>
<BodyText size="medium">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</BodyText>
<BodyText size="large">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</BodyText>
</Flex>
<CanvasProvider theme={{canvas: {direction: ContentDirection.RTL}}}>
<Flex flexDirection="column" gap="xxs">
<Subtext size="large">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</Subtext>
<BodyText size="small">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</BodyText>
<BodyText size="medium">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</BodyText>
<BodyText size="large">
The quick <ExternalHyperlink>brown fox</ExternalHyperlink> jumps over the lazy dog
The quick{' '}
<ExternalHyperlink iconLabel="Opens link in new window">brown fox</ExternalHyperlink>{' '}
jumps over the lazy dog
</BodyText>
</Flex>
</CanvasProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export const useComboboxInputConstrained = createElemPropsHook(useComboboxModel)
model.onFilterChange?.(event);
return null; // Prevent further `onChange` callbacks from firing
},

name: null,
disabled,
/**
Expand Down
5 changes: 4 additions & 1 deletion modules/react/skeleton/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export {Skeleton} from './lib/Skeleton';
export * from './lib/Skeleton';
export {skeletonTextStencil} from './lib/parts/SkeletonText';
export {skeletonShapeStencil} from './lib/parts/SkeletonShape';
export {skeletonHeaderStencil} from './lib/parts/SkeletonHeader';

0 comments on commit 8690580

Please sign in to comment.