Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add Image component and CDN src support to Graphic component #3062

Open
wants to merge 9 commits into
base: support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .storybook/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// and will rewrite the URL to point to the correct URL for the story. The Storybook key will be
// rewritten to something like `?path=/docs/${id}`
const routes = {
'/assets/accent-icons/': 'tokens-icon--accent-icon',
'/assets/applet-icons/': 'tokens-icon--applet-icon',
'/assets/applet-icons/': 'tokens-icon--applet-icon',
'/assets/system-icons/': 'tokens-icon--system-icon',
'/assets/accent-icons/': 'assets-icons-list--accent-icon-list',
'/assets/applet-icons/': 'assets-icons-list--applet-icon-list',
'/assets/system-icons/': 'assets-icons-list--applet-icon-list',
'/components/buttons/action-bar/': 'components-buttons-action-bar--basic',
'/components/buttons/button/': 'components-buttons--primary',
'/components/buttons/segmented-control/': 'preview-segmented-control--basic',
Expand Down
15 changes: 15 additions & 0 deletions modules/docs/mdx/11.0-UPGRADE-GUIDE.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ A note to the reader:
- [Styling API and CSS Tokens](#styling-api-and-css-tokens)
- [CountBadge](#count-badge)
- [Form Field Preview](#form-field-preview)
- [Graphic](#graphic)
- [Icons](#icons)
- [Image](#image)
- [Status Indicator (Preview)](#status-indicator-preview)
- [Table](#table)
- [Text](#text)
Expand Down Expand Up @@ -636,6 +638,12 @@ to check your logic to make sure it sets the appropaite value to the prop.
> **Note:** If you use your own custom `input` you will need to handle the styling for error and
> alert states.

### Graphic

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

We've updated `Graphic` and its `src` prop to accept a `string` value to support images loaded from a CDN or SAS. The previous API is still supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to add this to the upgrade guide for people moving from v10 to v11

### Icons

<div style={{display: 'inline-flex', gap: '.5rem'}}>
Expand Down Expand Up @@ -809,6 +817,13 @@ const MyComponent = StyledRadioButton('div')({
</MyComponent>;
```

### Image

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

We've added a new `Image` component under the `@workday/canvas-kit-react/icon` package. This component renders an `img` element and is meant to be used when you need more control over the image attributes like aspect ratio or object fit.


### Status Indicator (Preview)

<StatusIndicator variant="red" emphasis="low">
Expand Down
8 changes: 4 additions & 4 deletions modules/react/avatar/stories/stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ storiesOf('Components/Indicators/Avatar', module)
.add('Non-Square Image', () => (
<div className="story">
<h3>Original Rectangle Image</h3>
<img alt="" src="https://placekitten.com/g/450/200" />
<img alt="" src="https://i.imgur.com/f3FZv3H.jpeg" />
<h3>Using Object Fit on a Rectangle Image</h3>
<Avatar as="div" size={200} url="https://placekitten.com/g/450/200" objectFit="contain" />
<Avatar as="div" size={200} url="https://i.imgur.com/f3FZv3H.jpeg" objectFit="contain" />
<h3>Original Square Image</h3>
<img alt="" src="https://placekitten.com/g/450/450" />
<img alt="" src="https://i.imgur.com/himSfZn.jpeg" height={200} width={200} />
<h3>Using a Square Image</h3>
<Avatar as="div" size={200} url="https://placekitten.com/g/450/450" />
<Avatar as="div" size={200} url="https://i.imgur.com/himSfZn.jpeg" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These URLs were broken, so I updated them.

</div>
))
.add('Lazy Loading', () => (
Expand Down
1 change: 1 addition & 0 deletions modules/react/icon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export * from './lib/AppletIcon';
export * from './lib/SystemIcon';
export * from './lib/SystemIconCircle';
export * from './lib/Graphic';
export * from './lib/Image';
export {Svg, SvgProps, svgStencil} from './lib/Svg';
60 changes: 44 additions & 16 deletions modules/react/icon/lib/Graphic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import * as React from 'react';
import {CanvasGraphic, CanvasIconTypes} from '@workday/design-assets-types';
import {CSSObject} from '@emotion/styled';
import {Svg, SvgProps, svgStencil} from './Svg';
import {createComponent} from '@workday/canvas-kit-react/common';
import {createComponent, ExtractProps} from '@workday/canvas-kit-react/common';
import {createStencil, handleCsProp, px2rem} from '@workday/canvas-kit-styling';
import {Image} from './Image';

/**
* @deprecated Interface `GraphicStyles` will be removed in a future version. `grow` prop will be moved inside `GraphicProps`.
Expand All @@ -30,9 +31,13 @@ export interface GraphicProps extends GraphicStyles, Pick<SvgProps, 'shouldMirro
/**
* The graphic to display from `@workday/canvas-graphics-web`.
*/
src: CanvasGraphic;
src: CanvasGraphic | string;
}

type GraphicsImageProps = ExtractProps<typeof Image>;

export type GraphicsImageOrSvgProps = GraphicProps | GraphicsImageProps;

/**
* @deprecated `graphicStyles` will be removed in in a future version as a part of implementation of stencils and new tokens. Consider to use `graphicStencil` instead.
*/
Expand Down Expand Up @@ -66,6 +71,18 @@ export const graphicStyles = ({width, height, grow}: GraphicStyles): CSSObject =
return {};
};

type GraphicImageProps = ExtractProps<typeof Image>;

/**
* Returns an overloaded functional component that uses Graphic props by default.
*/
type GraphicOverload = {
(props: {src: CanvasGraphic} & GraphicProps & {ref?: React.Ref<HTMLElement>}): React.ReactElement;
(
props: {src: string} & GraphicImageProps & {ref?: React.Ref<HTMLImageElement>}
): React.ReactElement;
};

export const graphicStencil = createStencil({
extends: svgStencil,
base: {},
Expand All @@ -79,23 +96,34 @@ export const graphicStencil = createStencil({
},
});

export const Graphic = createComponent('span')({
export const Graphic: GraphicOverload = createComponent('span')({
displayName: 'Graphic',
Component: ({grow, width, height, ...elemProps}: GraphicProps, ref, Element) => {
Component: ({src, ...elemProps}: GraphicProps, ref, Element) => {
return (
<Svg
type={CanvasIconTypes.Graphic}
as={Element}
ref={ref}
{...handleCsProp(
elemProps,
graphicStencil({
grow,
width: typeof width === 'number' ? px2rem(width) : width,
height: typeof height === 'number' ? px2rem(height) : height,
})
<>
{typeof src === 'string' && typeof src !== 'object' ? (
<Image as={'img'} src={src} {...handleCsProp(elemProps)} />
) : (
<Svg
type={CanvasIconTypes.Graphic}
as={Element}
ref={ref}
src={src}
{...handleCsProp(
elemProps,
graphicStencil({
grow: elemProps.grow,
width:
typeof elemProps.width === 'number' ? px2rem(elemProps.width) : elemProps.width,
height:
typeof elemProps.height === 'number'
? px2rem(elemProps.height)
: elemProps.height,
})
)}
/>
)}
/>
</>
);
},
});
13 changes: 13 additions & 0 deletions modules/react/icon/lib/Image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react';

import {createComponent} from '@workday/canvas-kit-react/common';
import {CSProps, handleCsProp} from '@workday/canvas-kit-styling';

export interface ImageProps extends CSProps {}

export const Image = createComponent('img')({
displayName: 'Image',
Component: ({...elemProps}: ImageProps, ref, Element) => {
return <Element ref={ref} {...handleCsProp(elemProps)} />;
},
});
29 changes: 0 additions & 29 deletions modules/react/icon/stories/Assets.stories.mdx

This file was deleted.

31 changes: 31 additions & 0 deletions modules/react/icon/stories/IconsList.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {SystemIconList} from './examples/IconsList/IconList';
import {AppletIconList} from './examples/IconsList/AppletIconList';
import {AccentIconList} from './examples/IconsList/AccentIconList';
import {Overview} from './examples/Overview'

<Meta title="Assets/Icons List" />

## Overview

<ExampleCodeBlock code={Overview} />

## Accent Icon List

Accent Icons add clarity, and visual interest, they bring delight to the experience by communicating
the overall tone and meaning of a page.

<ExampleCodeBlock code={AccentIconList} />

## Applet Icon List

Applet Icons convey entry points, categories of actions, or information sources on the Workday
homepage.

<ExampleCodeBlock code={AppletIconList} />

## System Icon List

System Icons are symbols used to convey simple actions and functions, they are the most common icons
encountered in products and help communicate metaphors at a glance.

<ExampleCodeBlock code={SystemIconList} />
52 changes: 52 additions & 0 deletions modules/react/icon/stories/Image.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

import {SymbolDoc} from '@workday/canvas-kit-docs';
import {Basic} from './examples/Image/Basic';
import {FromFileSystem} from './examples/Image/FromFileSystem';

<Meta title="Images and Icons/Image" />

# Canvas Kit Image

Represents an `img` element.

## Installation

```sh
yarn add @workday/canvas-kit-react
```

## Usage

## Basic

The `Image` component is useful when trying to render raster files or images that need additional styling like aspect ratio or object fit. It renders an `img` element and therefore you have access to all [attributes and props](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) of a native `img` tag.

<ExampleCodeBlock code={Basic} />

## From File System

<ExampleCodeBlock code={FromFileSystem} />

## Accessibility

### Alt Text (alt):
- Always provide descriptive alt text for images. This helps screen readers convey the purpose or content of the image to visually impaired users.
- Use meaningful descriptions that explain the image's context in the UI.
- If the image is decorative, use an empty alt attribute (alt=""), which signals assistive technologies to ignore the image.

### Captioning (caption):

- Include captions for images where additional explanatory text is required.
- Captions should be used for graphs, charts, or any image requiring a detailed explanation.

### Role and ARIA Attributes:

- Avoid adding ARIA roles such as role="img" unless the component uses non-standard HTML elements.
- Default `<img>` elements are already recognized as images.
- Use ARIA attributes only when needed (e.g., aria-describedby for complex images with external descriptions).

## API

<SymbolDoc name="Image" fileName="/react/" />


Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const styleOverrides = {
}),
iconGroupContainer: createStyles({
flexWrap: 'wrap',
maxHeight: 300,
overflowY: 'scroll',
}),
individualIconContainer: createStyles({
alignItems: 'center',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const styleOverrides = {
}),
iconGroupContainer: createStyles({
flexWrap: 'wrap',
maxHeight: 300,
overflowY: 'scroll',
}),
individualIconContainer: createStyles({
alignItems: 'center',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const styleOverrides = {
}),
firstChildContainer: createStyles({
flexWrap: 'wrap',
maxHeight: 300,
overflowY: 'scroll',
}),
secondChildContainer: createStyles({
alignItems: 'center',
Expand Down
23 changes: 23 additions & 0 deletions modules/react/icon/stories/examples/Image/Basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import {Flex} from '@workday/canvas-kit-react/layout';
import {Image} from '@workday/canvas-kit-react/icon';

import {createStyles} from '@workday/canvas-kit-styling';

const styleOverrides = {
parentContainer: createStyles({
maxHeight: 300,
}),
};

export const Basic = () => {
return (
<Flex cs={styleOverrides.parentContainer}>
<Image
src="https://i.imgur.com/f3FZv3H.jpeg"
cs={{objectFit: 'cover', height: 200}}
alt="Image of a cat pretending to be a scientist with beakers and a chalkboard behind it"
/>
</Flex>
);
};
21 changes: 21 additions & 0 deletions modules/react/icon/stories/examples/Image/FromFileSystem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import {Flex} from '@workday/canvas-kit-react/layout';
import {Image} from '@workday/canvas-kit-react/icon';
import {createStyles} from '@workday/canvas-kit-styling';

// @ts-ignore: Cannot find module error
import catImage from '../images/cat.jpg';

const styleOverrides = {
parentContainer: createStyles({
maxHeight: 300,
}),
};

export const FromFileSystem = () => {
return (
<Flex cs={styleOverrides.parentContainer}>
<Image src={catImage} cs={{objectFit: 'cover', height: 200}} alt="Image of a cat mid yawn" />
</Flex>
);
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading