From dfe10a4fcb97b4e656a964dcaddac970443ed316 Mon Sep 17 00:00:00 2001 From: Hale Rankin Date: Tue, 21 Feb 2023 12:05:25 -0800 Subject: [PATCH 1/7] Adds Image web component. --- packages/web-components/src/image/define.ts | 4 + .../src/image/image.definition.ts | 17 ++ .../web-components/src/image/image.docs.md | 83 ++++++ .../web-components/src/image/image.options.ts | 46 ++++ .../web-components/src/image/image.stories.ts | 249 ++++++++++++++++++ .../web-components/src/image/image.styles.ts | 75 ++++++ .../src/image/image.template.ts | 8 + packages/web-components/src/image/image.ts | 64 +++++ packages/web-components/src/image/index.ts | 5 + packages/web-components/src/index.ts | 2 +- 10 files changed, 552 insertions(+), 1 deletion(-) create mode 100644 packages/web-components/src/image/define.ts create mode 100644 packages/web-components/src/image/image.definition.ts create mode 100644 packages/web-components/src/image/image.docs.md create mode 100644 packages/web-components/src/image/image.options.ts create mode 100644 packages/web-components/src/image/image.stories.ts create mode 100644 packages/web-components/src/image/image.styles.ts create mode 100644 packages/web-components/src/image/image.template.ts create mode 100644 packages/web-components/src/image/image.ts create mode 100644 packages/web-components/src/image/index.ts diff --git a/packages/web-components/src/image/define.ts b/packages/web-components/src/image/define.ts new file mode 100644 index 0000000000000..002c77e34e522 --- /dev/null +++ b/packages/web-components/src/image/define.ts @@ -0,0 +1,4 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { definition } from './image.definition.js'; + +definition.define(FluentDesignSystem.registry); diff --git a/packages/web-components/src/image/image.definition.ts b/packages/web-components/src/image/image.definition.ts new file mode 100644 index 0000000000000..4e452fcc3a13e --- /dev/null +++ b/packages/web-components/src/image/image.definition.ts @@ -0,0 +1,17 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { Image } from './image.js'; +import { template } from './image.template.js'; +import { styles } from './image.styles.js'; + +/** + * The Fluent Image Element + * + * @public + * @remarks + * HTML Element: \ + */ +export const definition = Image.compose({ + name: `${FluentDesignSystem.prefix}-image`, + template, + styles, +}); diff --git a/packages/web-components/src/image/image.docs.md b/packages/web-components/src/image/image.docs.md new file mode 100644 index 0000000000000..30cf021e7fb3f --- /dev/null +++ b/packages/web-components/src/image/image.docs.md @@ -0,0 +1,83 @@ +# Fluent Image Component + +## Component Description + +Images, like photos and illustrations, help reinforce a message and express your product or app’s style. + +## Design Spec + +[Image Spec in Figma](https://www.figma.com/file/05wt6TAsEmgsCVZfPrpcWx/Image?t=uEvu1KnTefdTZHJC-6) + +## Engineering Spec + +### Inputs + +**content** + +- @attr public alt: string | Requires description if image role is not set to presentation. +- @attr public role: string +- @attr public src: string + +**booleans** + +- @attr public block: boolean | false +- @attr public border: boolean | false +- @attr public margin: boolean | false +- @attr public shadow: boolean | false + +**options** + +- @attr public border-radius: 'small' | 'medium' | 'large' | 'x-large' +- @attr public fit: 'none' | 'center' | 'contain' | 'cover' | 'default' +- @attr public shape: 'square' | 'rounded' | 'circular' + +### Slots + +1 slot for developer to add element. + +## Accessibility + +The image element requires an alt tag when not used in role: presentation. + +## Preparation + +This will extend the FASTElement. + +This appears to be indentical to the [Fluent UI React V9 Image component](https://master--628d031b55e942004ac95df1.chromatic.com/?path=/docs/components-image--default) in terms of props except for the following: + +margin: optional 16px margin + +However, when looking at the [component code](https://github.com/microsoft/fluentui/blob/master/packages/react/src/components/Image), they differ significantly. + +Open GitHub issues related to Image component + +- [Feature request](https://github.com/microsoft/fluentui/issues/26452) +- [Bug](https://github.com/microsoft/fluentui/issues/26399) + +## Implementation + +@miro - are these necessary? + +- [?] Initial conformance and unit tests (validate basic functionality) + + - [?] README.md covering basic usage + +- [x] Uses design tokens for styling +- [?] Renders correctly in High Contrast mode + +## Validation + +@miro - are these necessary? + +- [ ] [Add tests](https://github.com/microsoft/fluentui/wiki/Component-Implementation-Guide#tests) + - [ ] Unit and conformance tests + - [ ] Bundle size fixtures + - [ ] Performance test scenario + - [ ] Accessibility behavior tests + - [ ] Create an issue and run [manual accessibility tests](https://github.com/microsoft/fluentui/wiki/Manual-Accessibility-Review-Checklist): [link to issue] +- [ ] [Validate with partners](https://github.com/microsoft/fluentui/wiki/Component-Implementation-Guide#validation) +- [ ] [Finalize documentation](https://github.com/microsoft/fluentui/wiki/Component-Implementation-Guide#finalize-documentation) + - [ ] Review and add any missing storybook stories + - [ ] Finalize migration guide + - [ ] In package.json: Remove the alpha/beta tag from the version number in package.json + - [ ] In package.json: Change beachball's `disallowedChangeTypes` to `"major", "prerelease"` diff --git a/packages/web-components/src/image/image.options.ts b/packages/web-components/src/image/image.options.ts new file mode 100644 index 0000000000000..34a7a07e1fc3e --- /dev/null +++ b/packages/web-components/src/image/image.options.ts @@ -0,0 +1,46 @@ +import { ValuesOf } from '@microsoft/fast-foundation'; + +/** + * Border radius + * @public + */ +export const ImageBorderRadius = { + small: 'small', + medium: 'medium', + large: 'large', + xlarge: 'x-large', +} as const; +/** + * Types for border radius + * @public + */ +export type ImageBorderRadius = ValuesOf; + +/** + * Image fit + * @public + */ +export const ImageFit = { + none: 'none', + center: 'center', + contain: 'contain', + cover: 'cover', + default: 'default', +} as const; +/** + * Types for image fit + * @public + */ +export type ImageFit = ValuesOf; + +/** + * Image shape + * @public + */ +export const ImageShape = { + circular: 'circular', + rounded: 'rounded', + square: 'square', +} as const; + +export type ImageShape = ValuesOf; diff --git a/packages/web-components/src/image/image.stories.ts b/packages/web-components/src/image/image.stories.ts new file mode 100644 index 0000000000000..74e2cdf04eb6d --- /dev/null +++ b/packages/web-components/src/image/image.stories.ts @@ -0,0 +1,249 @@ +import { html } from '@microsoft/fast-element'; +import type { Args, Meta } from '@storybook/html'; +import { renderComponent } from '../helpers.stories.js'; +import type { Image as FluentImage } from './image.js'; +import { ImageBorderRadius, ImageFit, ImageShape } from './image.options.js'; +import './define.js'; + +type ImageStoryArgs = Args & FluentImage; +type ImageStoryMeta = Meta; + +const imageTemplate = html` +
+ x.block} + ?border=${x => x.border} + border-radius=${x => x.borderRadius} + fit=${x => x.fit} + ?shadow=${x => x.shadow} + shape=${x => x.shape} + > + Short image description + Short image description + Short image description + Short image description + Short image description + +
+`; + +export default { + title: 'Components/Image', + args: { + block: false, + border: false, + shadow: false, + borderRadius: ImageBorderRadius.small, + fit: ImageFit.default, + shape: ImageShape.square, + }, + argTypes: { + alt: { + description: 'Alternate text description -- to be supplied by component consumer', + table: { + type: { + summary: + 'Required. Alt tag provides text attribution for images. Should be brief but accurate—one or two sentences that describe the image and its context. If the image represents a function, be sure to indicate that. If it’s meant to be consumed with other objects on the page, consider that as well. Don’t repeat information that’s on the page in alt text since screen readers will read it twice.', + }, + }, + }, + block: { + description: + 'An image can use the argument ‘block’ so that it’s width will expand to fiill the available container space.', + table: { + defaultValue: { + summary: false, + }, + }, + }, + border: { + description: 'Border surrounding image', + table: { + type: { + summary: 'Use this option to provide minimal visual separation between image and surrounding content.', + }, + defaultValue: { + summary: false, + }, + }, + }, + borderRadius: { + description: 'Optional border radius', + table: { + defaultValue: { + summary: 'small', + }, + }, + options: Object.values(ImageBorderRadius), + control: 'select', + }, + fit: { + description: 'Determines how the image will be scaled and positioned within its parent container.', + table: { + defaultValue: { + summary: 'default', + }, + }, + options: Object.values(ImageFit), + control: 'select', + }, + margin: { + description: 'Optional 16px margin -- to be supplied by component consumer', + }, + role: { + description: 'Aria role -- to be supplied by component consumer', + table: { + type: { + summary: + 'If images are solely decorative and don’t provide useful information or context, use role=”presentation” to hide them from assistive technologies.', + }, + }, + }, + shadow: { + description: 'Apply an optional box shadow to further separate the image from the background.', + table: { + type: { + summary: + 'To give an image additional prominence, use the shadow prop to make it appear elevated. Too many shadows can cause a busy layout, so use them sparingly.', + }, + defaultValue: { + summary: false, + }, + }, + }, + shape: { + description: 'Image shape', + table: { + defaultValue: { + summary: 'square', + }, + }, + options: Object.values(ImageShape), + control: 'select', + }, + src: { + description: 'Image source -- to be supplied by component consumer', + table: { + type: { + summary: 'Required', + }, + }, + }, + }, +} as ImageStoryMeta; + +export const Image = renderComponent(imageTemplate).bind({}); + +// Block layout +const imageLayoutBlock = html` +
+ + + + +
+`; +export const BlockLayout = renderComponent(imageLayoutBlock).bind({}); + +// Fit: None +const imageFitNoneLarge = html` +
+ + + +
+`; +export const ImageFitNoneLarge = renderComponent(imageFitNoneLarge).bind({}); + +const imageFitNoneSmall = html` +
+ + 200x100 placeholder + +
+`; +export const ImageFitNoneSmall = renderComponent(imageFitNoneSmall).bind({}); + +// Fit: Center +const imageFitCenterLarge = html` +
+ + + +
+`; +export const ImageFitCenterLarge = renderComponent(imageFitCenterLarge).bind({}); + +const imageFitCenterSmall = html` +
+ + image layout story + +
+`; +export const ImageFitCenterSmall = renderComponent(imageFitCenterSmall).bind({}); + +const imageFitContain = html` +
+ + image layout story + +
+`; +export const ImageFitContain = renderComponent(imageFitContain).bind({}); + +const imageFitContainTall = html` +
+ + image layout story + +
+`; +export const ImageFitContainTall = renderComponent(imageFitContainTall).bind({}); + +const imageFitContainWide = html` +
+ + image layout story + +
+`; +export const ImageFitContainWide = renderComponent(imageFitContainWide).bind({}); + +// Fit: Cover +const imageFitCoverSmall = html` +
+ + image layout story + +
+`; +export const ImageFitCoverSmall = renderComponent(imageFitCoverSmall).bind({}); + +const imageFitCoverMedium = html` +
+ + image layout story + +
+`; +export const ImageFitCoverMedium = renderComponent(imageFitCoverMedium).bind({}); + +const imageFitCoverLarge = html` +
+ + image layout story + +
+`; +export const ImageFitCoverLarge = renderComponent(imageFitCoverLarge).bind({}); + +// Fit: Default +const imageFitDefault = html` +
+ + image layout story + +
+`; +export const ImageFitDefault = renderComponent(imageFitDefault).bind({}); diff --git a/packages/web-components/src/image/image.styles.ts b/packages/web-components/src/image/image.styles.ts new file mode 100644 index 0000000000000..856bf3916556e --- /dev/null +++ b/packages/web-components/src/image/image.styles.ts @@ -0,0 +1,75 @@ +import { css } from '@microsoft/fast-element'; +import { + borderRadiusLarge, + borderRadiusMedium, + borderRadiusSmall, + borderRadiusXLarge, + colorNeutralStroke2, + shadow4, + strokeWidthThin, +} from '../theme/design-tokens.js'; + +/** Image styles + * + * @public + */ +export const styles = css` + :host ::slotted(img) { + box-sizing: border-box; + min-height: 8px; + min-width: 8px; + display: inline-block; + } + :host([block]) ::slotted(img) { + width: 100%; + height: auto; + } + :host([border]) ::slotted(img) { + border: ${strokeWidthThin} solid ${colorNeutralStroke2}; + } + :host([fit='none']) ::slotted(img) { + object-fit: none; + object-position: top left; + height: 100%; + width: 100%; + } + :host([fit='center']) ::slotted(img) { + object-fit: none; + object-position: center; + height: 100%; + width: 100%; + } + :host([fit='contain']) ::slotted(img) { + object-fit: contain; + object-position: center; + height: 100%; + width: 100%; + } + :host([fit='cover']) ::slotted(img) { + object-fit: cover; + object-position: center; + height: 100%; + width: 100%; + } + :host([shadow]) ::slotted(img) { + box-shadow: ${shadow4}; + } + :host([shape='circular']) ::slotted(img) { + border-radius: 999em; + } + :host([shape='rounded'][border-radius='small']) ::slotted(img) { + border-radius: ${borderRadiusSmall}; + } + :host([shape='rounded'][border-radius='medium']) ::slotted(img) { + border-radius: ${borderRadiusMedium}; + } + :host([shape='rounded'][border-radius='large']) ::slotted(img) { + border-radius: ${borderRadiusLarge}; + } + :host([shape='rounded'][border-radius='x-large']) ::slotted(img) { + border-radius: ${borderRadiusXLarge}; + } + :host([shape='square']) ::slotted(img) { + border-radius: none; + } +`; diff --git a/packages/web-components/src/image/image.template.ts b/packages/web-components/src/image/image.template.ts new file mode 100644 index 0000000000000..9307a3c7d72ea --- /dev/null +++ b/packages/web-components/src/image/image.template.ts @@ -0,0 +1,8 @@ +import { ElementViewTemplate, html } from '@microsoft/fast-element'; +import type { Image } from './image.js'; + +/** + * Template for the Image component + * @public + */ +export const template: ElementViewTemplate = html``; diff --git a/packages/web-components/src/image/image.ts b/packages/web-components/src/image/image.ts new file mode 100644 index 0000000000000..e53c878bf0779 --- /dev/null +++ b/packages/web-components/src/image/image.ts @@ -0,0 +1,64 @@ +import { attr, FASTElement } from '@microsoft/fast-element'; +import { ImageBorderRadius, ImageFit, ImageShape } from './image.options.js'; + +/** + * The base class used for constucting a fluent image custom element + * @public + */ +export class Image extends FASTElement { + /** + * Image layout + * + * @public + * @remarks + * HTML attribute: block. + */ + @attr({ mode: 'boolean' }) + public block?: boolean; + /** + * Image border + * + * @public + * @remarks + * HTML attribute: border. + */ + @attr({ mode: 'boolean' }) + public border?: boolean; + /** + * Image shadow + * + * @public + * @remarks + * HTML attribute: shadow. + */ + @attr({ mode: 'boolean' }) + public shadow?: boolean; + + /** + * Border Radius + * + * @public + * @remarks + * Degree of border roundness. + */ + @attr({ attribute: 'border-radius' }) + public borderRadius: ImageBorderRadius; + /** + * Image fit + * + * @public + * @remarks + * HTML attribute: fit. + */ + @attr + public fit: ImageFit; + /** + * Image shape + * + * @public + * @remarks + * HTML attribute: shape. + */ + @attr + public shape: ImageShape; +} diff --git a/packages/web-components/src/image/index.ts b/packages/web-components/src/image/index.ts new file mode 100644 index 0000000000000..29839a1248865 --- /dev/null +++ b/packages/web-components/src/image/index.ts @@ -0,0 +1,5 @@ +export * from './image.js'; +export * from './image.options.js'; +export { definition as ImageDefinition } from './image.definition.js'; +export { template as ImageTemplate } from './image.template.js'; +export { styles as ImageStyles } from './image.styles.js'; diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts index 78cf3190790a6..9dd668b73b0fc 100644 --- a/packages/web-components/src/index.ts +++ b/packages/web-components/src/index.ts @@ -1,7 +1,7 @@ export * from './badge/index.js'; export * from './counter-badge/index.js'; +export * from './image/index.js'; export * from './progress-bar/index.js'; export * from './spinner/index.js'; export * from './text/index.js'; - export * from './theme/index.js'; From a4700cf8560628aa1e26d45242d318116d559575 Mon Sep 17 00:00:00 2001 From: Hale Rankin Date: Wed, 22 Feb 2023 13:45:47 -0800 Subject: [PATCH 2/7] Removes unused portions of the doc file (now spec.md). Renames and simplifies the bordered attribute. Removes multiple image from first story. Adjusts style attribute selctor for bordered. --- .../image/{image.docs.md => image.spec.md} | 23 +------------ .../web-components/src/image/image.stories.ts | 34 ++++++++----------- .../web-components/src/image/image.styles.ts | 2 +- packages/web-components/src/image/image.ts | 2 +- packages/web-components/src/index.ts | 1 + 5 files changed, 19 insertions(+), 43 deletions(-) rename packages/web-components/src/image/{image.docs.md => image.spec.md} (61%) diff --git a/packages/web-components/src/image/image.docs.md b/packages/web-components/src/image/image.spec.md similarity index 61% rename from packages/web-components/src/image/image.docs.md rename to packages/web-components/src/image/image.spec.md index 30cf021e7fb3f..67a1b740d0a6b 100644 --- a/packages/web-components/src/image/image.docs.md +++ b/packages/web-components/src/image/image.spec.md @@ -56,28 +56,7 @@ Open GitHub issues related to Image component ## Implementation -@miro - are these necessary? - -- [?] Initial conformance and unit tests (validate basic functionality) - - - [?] README.md covering basic usage +- [?] README.md covering basic usage - [x] Uses design tokens for styling - [?] Renders correctly in High Contrast mode - -## Validation - -@miro - are these necessary? - -- [ ] [Add tests](https://github.com/microsoft/fluentui/wiki/Component-Implementation-Guide#tests) - - [ ] Unit and conformance tests - - [ ] Bundle size fixtures - - [ ] Performance test scenario - - [ ] Accessibility behavior tests - - [ ] Create an issue and run [manual accessibility tests](https://github.com/microsoft/fluentui/wiki/Manual-Accessibility-Review-Checklist): [link to issue] -- [ ] [Validate with partners](https://github.com/microsoft/fluentui/wiki/Component-Implementation-Guide#validation) -- [ ] [Finalize documentation](https://github.com/microsoft/fluentui/wiki/Component-Implementation-Guide#finalize-documentation) - - [ ] Review and add any missing storybook stories - - [ ] Finalize migration guide - - [ ] In package.json: Remove the alpha/beta tag from the version number in package.json - - [ ] In package.json: Change beachball's `disallowedChangeTypes` to `"major", "prerelease"` diff --git a/packages/web-components/src/image/image.stories.ts b/packages/web-components/src/image/image.stories.ts index 74e2cdf04eb6d..22d6de4e78945 100644 --- a/packages/web-components/src/image/image.stories.ts +++ b/packages/web-components/src/image/image.stories.ts @@ -12,17 +12,13 @@ const imageTemplate = html`
x.block} - ?border=${x => x.border} + ?bordered=${x => x.bordered} border-radius=${x => x.borderRadius} fit=${x => x.fit} ?shadow=${x => x.shadow} shape=${x => x.shape} > Short image description - Short image description - Short image description - Short image description - Short image description
`; @@ -31,7 +27,7 @@ export default { title: 'Components/Image', args: { block: false, - border: false, + bordered: false, shadow: false, borderRadius: ImageBorderRadius.small, fit: ImageFit.default, @@ -56,7 +52,7 @@ export default { }, }, }, - border: { + bordered: { description: 'Border surrounding image', table: { type: { @@ -137,7 +133,7 @@ export const Image = renderComponent(imageTemplate).bind({}); // Block layout const imageLayoutBlock = html`
- + @@ -148,7 +144,7 @@ export const BlockLayout = renderComponent(imageLayoutBlock).bind({}); // Fit: None const imageFitNoneLarge = html`
- +
@@ -157,7 +153,7 @@ export const ImageFitNoneLarge = renderComponent(imageFitNoneLarge).bind({}); const imageFitNoneSmall = html`
- + 200x100 placeholder
@@ -167,7 +163,7 @@ export const ImageFitNoneSmall = renderComponent(imageFitNoneSmall).bind({}); // Fit: Center const imageFitCenterLarge = html`
- +
@@ -176,7 +172,7 @@ export const ImageFitCenterLarge = renderComponent(imageFitCenterLarge).bind({}) const imageFitCenterSmall = html`
- + image layout story
@@ -185,7 +181,7 @@ export const ImageFitCenterSmall = renderComponent(imageFitCenterSmall).bind({}) const imageFitContain = html`
- + image layout story
@@ -194,7 +190,7 @@ export const ImageFitContain = renderComponent(imageFitContain).bind({}); const imageFitContainTall = html`
- + image layout story
@@ -203,7 +199,7 @@ export const ImageFitContainTall = renderComponent(imageFitContainTall).bind({}) const imageFitContainWide = html`
- + image layout story
@@ -213,7 +209,7 @@ export const ImageFitContainWide = renderComponent(imageFitContainWide).bind({}) // Fit: Cover const imageFitCoverSmall = html`
- + image layout story
@@ -222,7 +218,7 @@ export const ImageFitCoverSmall = renderComponent(imageFitCoverSmall).bind({}); const imageFitCoverMedium = html`
- + image layout story
@@ -231,7 +227,7 @@ export const ImageFitCoverMedium = renderComponent(imageFitCoverMedium).bind({}) const imageFitCoverLarge = html`
- + image layout story
@@ -241,7 +237,7 @@ export const ImageFitCoverLarge = renderComponent(imageFitCoverLarge).bind({}); // Fit: Default const imageFitDefault = html`
- + image layout story
diff --git a/packages/web-components/src/image/image.styles.ts b/packages/web-components/src/image/image.styles.ts index 856bf3916556e..d530d9f7c5d2a 100644 --- a/packages/web-components/src/image/image.styles.ts +++ b/packages/web-components/src/image/image.styles.ts @@ -24,7 +24,7 @@ export const styles = css` width: 100%; height: auto; } - :host([border]) ::slotted(img) { + :host([bordered]) ::slotted(img) { border: ${strokeWidthThin} solid ${colorNeutralStroke2}; } :host([fit='none']) ::slotted(img) { diff --git a/packages/web-components/src/image/image.ts b/packages/web-components/src/image/image.ts index e53c878bf0779..bb01505e45a2b 100644 --- a/packages/web-components/src/image/image.ts +++ b/packages/web-components/src/image/image.ts @@ -23,7 +23,7 @@ export class Image extends FASTElement { * HTML attribute: border. */ @attr({ mode: 'boolean' }) - public border?: boolean; + public bordered?: boolean; /** * Image shadow * diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts index 9dd668b73b0fc..e8a9f0c038127 100644 --- a/packages/web-components/src/index.ts +++ b/packages/web-components/src/index.ts @@ -4,4 +4,5 @@ export * from './image/index.js'; export * from './progress-bar/index.js'; export * from './spinner/index.js'; export * from './text/index.js'; + export * from './theme/index.js'; From e37bc5792b36a3d0089a7c7a5034aecab3249848 Mon Sep 17 00:00:00 2001 From: Hale Rankin Date: Wed, 22 Feb 2023 15:07:35 -0800 Subject: [PATCH 3/7] Removes unused CSS. Changes dimension of image used in first story. --- packages/web-components/src/image/image.stories.ts | 2 +- packages/web-components/src/image/image.styles.ts | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/web-components/src/image/image.stories.ts b/packages/web-components/src/image/image.stories.ts index 22d6de4e78945..c7964da92ba8f 100644 --- a/packages/web-components/src/image/image.stories.ts +++ b/packages/web-components/src/image/image.stories.ts @@ -18,7 +18,7 @@ const imageTemplate = html` ?shadow=${x => x.shadow} shape=${x => x.shape} > - Short image description + Short image description
`; diff --git a/packages/web-components/src/image/image.styles.ts b/packages/web-components/src/image/image.styles.ts index d530d9f7c5d2a..ecc3c662e1914 100644 --- a/packages/web-components/src/image/image.styles.ts +++ b/packages/web-components/src/image/image.styles.ts @@ -69,7 +69,4 @@ export const styles = css` :host([shape='rounded'][border-radius='x-large']) ::slotted(img) { border-radius: ${borderRadiusXLarge}; } - :host([shape='square']) ::slotted(img) { - border-radius: none; - } `; From d6ef3cb706758e4c82cf19903e66bb31aac888d8 Mon Sep 17 00:00:00 2001 From: Hale Rankin Date: Wed, 22 Feb 2023 16:03:09 -0800 Subject: [PATCH 4/7] Removes borderRadius attribute and related story code and styles. Adds CSS Guidance to spec to convey details about margin and border-radius values. Cleaned up story code. --- .../web-components/src/image/image.options.ts | 16 -------------- .../web-components/src/image/image.spec.md | 20 ++++++++--------- .../web-components/src/image/image.stories.ts | 17 +------------- .../web-components/src/image/image.styles.ts | 22 +------------------ packages/web-components/src/image/image.ts | 12 +--------- 5 files changed, 13 insertions(+), 74 deletions(-) diff --git a/packages/web-components/src/image/image.options.ts b/packages/web-components/src/image/image.options.ts index 34a7a07e1fc3e..fe68ac66892e1 100644 --- a/packages/web-components/src/image/image.options.ts +++ b/packages/web-components/src/image/image.options.ts @@ -1,21 +1,5 @@ import { ValuesOf } from '@microsoft/fast-foundation'; -/** - * Border radius - * @public - */ -export const ImageBorderRadius = { - small: 'small', - medium: 'medium', - large: 'large', - xlarge: 'x-large', -} as const; -/** - * Types for border radius - * @public - */ -export type ImageBorderRadius = ValuesOf; - /** * Image fit * @public diff --git a/packages/web-components/src/image/image.spec.md b/packages/web-components/src/image/image.spec.md index 67a1b740d0a6b..d2dba58db8142 100644 --- a/packages/web-components/src/image/image.spec.md +++ b/packages/web-components/src/image/image.spec.md @@ -22,12 +22,10 @@ Images, like photos and illustrations, help reinforce a message and express your - @attr public block: boolean | false - @attr public border: boolean | false -- @attr public margin: boolean | false - @attr public shadow: boolean | false **options** -- @attr public border-radius: 'small' | 'medium' | 'large' | 'x-large' - @attr public fit: 'none' | 'center' | 'contain' | 'cover' | 'default' - @attr public shape: 'square' | 'rounded' | 'circular' @@ -43,12 +41,6 @@ The image element requires an alt tag when not used in role: presentation. This will extend the FASTElement. -This appears to be indentical to the [Fluent UI React V9 Image component](https://master--628d031b55e942004ac95df1.chromatic.com/?path=/docs/components-image--default) in terms of props except for the following: - -margin: optional 16px margin - -However, when looking at the [component code](https://github.com/microsoft/fluentui/blob/master/packages/react/src/components/Image), they differ significantly. - Open GitHub issues related to Image component - [Feature request](https://github.com/microsoft/fluentui/issues/26452) @@ -56,7 +48,15 @@ Open GitHub issues related to Image component ## Implementation -- [?] README.md covering basic usage +### CSS Guidance - [x] Uses design tokens for styling -- [?] Renders correctly in High Contrast mode + +An optional border-radius can be expressed using the following design tokens: + +- borderRadiusSmall, +- borderRadiusMedium, +- borderRadiusLarge +- borderRadiusXLarge + +An optional 16px margin can be added to the image to separate it from surrounding content. diff --git a/packages/web-components/src/image/image.stories.ts b/packages/web-components/src/image/image.stories.ts index c7964da92ba8f..b5ed33ed14daa 100644 --- a/packages/web-components/src/image/image.stories.ts +++ b/packages/web-components/src/image/image.stories.ts @@ -2,7 +2,7 @@ import { html } from '@microsoft/fast-element'; import type { Args, Meta } from '@storybook/html'; import { renderComponent } from '../helpers.stories.js'; import type { Image as FluentImage } from './image.js'; -import { ImageBorderRadius, ImageFit, ImageShape } from './image.options.js'; +import { ImageFit, ImageShape } from './image.options.js'; import './define.js'; type ImageStoryArgs = Args & FluentImage; @@ -13,7 +13,6 @@ const imageTemplate = html` x.block} ?bordered=${x => x.bordered} - border-radius=${x => x.borderRadius} fit=${x => x.fit} ?shadow=${x => x.shadow} shape=${x => x.shape} @@ -29,7 +28,6 @@ export default { block: false, bordered: false, shadow: false, - borderRadius: ImageBorderRadius.small, fit: ImageFit.default, shape: ImageShape.square, }, @@ -63,16 +61,6 @@ export default { }, }, }, - borderRadius: { - description: 'Optional border radius', - table: { - defaultValue: { - summary: 'small', - }, - }, - options: Object.values(ImageBorderRadius), - control: 'select', - }, fit: { description: 'Determines how the image will be scaled and positioned within its parent container.', table: { @@ -83,9 +71,6 @@ export default { options: Object.values(ImageFit), control: 'select', }, - margin: { - description: 'Optional 16px margin -- to be supplied by component consumer', - }, role: { description: 'Aria role -- to be supplied by component consumer', table: { diff --git a/packages/web-components/src/image/image.styles.ts b/packages/web-components/src/image/image.styles.ts index ecc3c662e1914..23de7e0224ee3 100644 --- a/packages/web-components/src/image/image.styles.ts +++ b/packages/web-components/src/image/image.styles.ts @@ -1,13 +1,5 @@ import { css } from '@microsoft/fast-element'; -import { - borderRadiusLarge, - borderRadiusMedium, - borderRadiusSmall, - borderRadiusXLarge, - colorNeutralStroke2, - shadow4, - strokeWidthThin, -} from '../theme/design-tokens.js'; +import { colorNeutralStroke2, shadow4, strokeWidthThin } from '../theme/design-tokens.js'; /** Image styles * @@ -57,16 +49,4 @@ export const styles = css` :host([shape='circular']) ::slotted(img) { border-radius: 999em; } - :host([shape='rounded'][border-radius='small']) ::slotted(img) { - border-radius: ${borderRadiusSmall}; - } - :host([shape='rounded'][border-radius='medium']) ::slotted(img) { - border-radius: ${borderRadiusMedium}; - } - :host([shape='rounded'][border-radius='large']) ::slotted(img) { - border-radius: ${borderRadiusLarge}; - } - :host([shape='rounded'][border-radius='x-large']) ::slotted(img) { - border-radius: ${borderRadiusXLarge}; - } `; diff --git a/packages/web-components/src/image/image.ts b/packages/web-components/src/image/image.ts index bb01505e45a2b..ee3c055b2c6ed 100644 --- a/packages/web-components/src/image/image.ts +++ b/packages/web-components/src/image/image.ts @@ -1,5 +1,5 @@ import { attr, FASTElement } from '@microsoft/fast-element'; -import { ImageBorderRadius, ImageFit, ImageShape } from './image.options.js'; +import { ImageFit, ImageShape } from './image.options.js'; /** * The base class used for constucting a fluent image custom element @@ -33,16 +33,6 @@ export class Image extends FASTElement { */ @attr({ mode: 'boolean' }) public shadow?: boolean; - - /** - * Border Radius - * - * @public - * @remarks - * Degree of border roundness. - */ - @attr({ attribute: 'border-radius' }) - public borderRadius: ImageBorderRadius; /** * Image fit * From 3ddd7eef8c77369017ee4d95f91d76dc64b784c6 Mon Sep 17 00:00:00 2001 From: Hale Rankin Date: Thu, 23 Feb 2023 11:00:14 -0800 Subject: [PATCH 5/7] Records results of yarn change --- ...eb-components-a862230b-9028-4c6a-8a43-3be819a6128e.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json diff --git a/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json b/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json new file mode 100644 index 0000000000000..a25c256678b37 --- /dev/null +++ b/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Uncouples default state from their attributes; now handled via CSS.", + "packageName": "@fluentui/web-components", + "email": "harankin@microsoft.com", + "dependentChangeType": "patch" +} From ede43a4afa88ad37964d683ba994bac380e7e87b Mon Sep 17 00:00:00 2001 From: Hale Rankin Date: Thu, 23 Feb 2023 12:32:33 -0800 Subject: [PATCH 6/7] Updates package with reference to the component. Makes fit and shape optional. Replaces hard coded border radius value with token. --- packages/web-components/package.json | 4 ++++ packages/web-components/src/image/image.styles.ts | 4 ++-- packages/web-components/src/image/image.ts | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/web-components/package.json b/packages/web-components/package.json index 65c0e769ff89c..27cb97a7cc4d7 100644 --- a/packages/web-components/package.json +++ b/packages/web-components/package.json @@ -32,6 +32,10 @@ "types": "./dist/esm/counter-badge/define.d.ts", "default": "./dist/esm/counter-badge/define.js" }, + "./image": { + "types": "./dist/esm/image/define.d.ts", + "default": "./dist/esm/image/define.js" + }, "./text": { "types": "./dist/esm/text/define.d.ts", "default": "./dist/esm/text/define.js" diff --git a/packages/web-components/src/image/image.styles.ts b/packages/web-components/src/image/image.styles.ts index 23de7e0224ee3..34c04cf72590e 100644 --- a/packages/web-components/src/image/image.styles.ts +++ b/packages/web-components/src/image/image.styles.ts @@ -1,5 +1,5 @@ import { css } from '@microsoft/fast-element'; -import { colorNeutralStroke2, shadow4, strokeWidthThin } from '../theme/design-tokens.js'; +import { borderRadiusCircular, colorNeutralStroke2, shadow4, strokeWidthThin } from '../theme/design-tokens.js'; /** Image styles * @@ -47,6 +47,6 @@ export const styles = css` box-shadow: ${shadow4}; } :host([shape='circular']) ::slotted(img) { - border-radius: 999em; + border-radius: ${borderRadiusCircular}; } `; diff --git a/packages/web-components/src/image/image.ts b/packages/web-components/src/image/image.ts index ee3c055b2c6ed..c93f4d22d4959 100644 --- a/packages/web-components/src/image/image.ts +++ b/packages/web-components/src/image/image.ts @@ -41,7 +41,7 @@ export class Image extends FASTElement { * HTML attribute: fit. */ @attr - public fit: ImageFit; + public fit?: ImageFit; /** * Image shape * @@ -50,5 +50,5 @@ export class Image extends FASTElement { * HTML attribute: shape. */ @attr - public shape: ImageShape; + public shape?: ImageShape; } From e8dcc4e1e58dd85ea49007e706904caa27034ccf Mon Sep 17 00:00:00 2001 From: Chris Holt Date: Fri, 24 Feb 2023 10:54:55 -0800 Subject: [PATCH 7/7] Update change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json Co-authored-by: Miroslav Stastny --- ...tui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json b/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json index a25c256678b37..5dc002fd61244 100644 --- a/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json +++ b/change/@fluentui-web-components-a862230b-9028-4c6a-8a43-3be819a6128e.json @@ -1,6 +1,6 @@ { "type": "prerelease", - "comment": "Uncouples default state from their attributes; now handled via CSS.", + "comment": "feat(image): Add image web component", "packageName": "@fluentui/web-components", "email": "harankin@microsoft.com", "dependentChangeType": "patch"