diff --git a/change/@microsoft-fast-foundation-28a53924-05c6-4a69-afa5-bbb8efebe05c.json b/change/@microsoft-fast-foundation-28a53924-05c6-4a69-afa5-bbb8efebe05c.json new file mode 100644 index 00000000000..dc2caa570e4 --- /dev/null +++ b/change/@microsoft-fast-foundation-28a53924-05c6-4a69-afa5-bbb8efebe05c.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Foundation: Update Progress templates (see https://github.com/microsoft/fast/pull/6799)", + "packageName": "@microsoft/fast-foundation", + "email": "47367562+bheston@users.noreply.github.com", + "dependentChangeType": "prerelease" +} diff --git a/packages/web-components/fast-foundation/docs/api-report.md b/packages/web-components/fast-foundation/docs/api-report.md index 77b70a95936..2b4f0ba1175 100644 --- a/packages/web-components/fast-foundation/docs/api-report.md +++ b/packages/web-components/fast-foundation/docs/api-report.md @@ -2550,14 +2550,21 @@ export type PickerOptions = { // @public export function pickerTemplate(options: PickerOptions): ElementViewTemplate; +// @public +export const progressIndicatorTemplate: ViewTemplate; + // @public export type ProgressOptions = { - indeterminateIndicator1?: StaticallyComposableHTML; - indeterminateIndicator2?: StaticallyComposableHTML; + determinateIndicator?: StaticallyComposableHTML; + indeterminateIndicator?: StaticallyComposableHTML; }; +// @public +export const progressRingIndicatorTemplate: ViewTemplate; + // @public export type ProgressRingOptions = { + determinateIndicator?: StaticallyComposableHTML; indeterminateIndicator?: StaticallyComposableHTML; }; diff --git a/packages/web-components/fast-foundation/src/progress-ring/index.ts b/packages/web-components/fast-foundation/src/progress-ring/index.ts index 5118a937e32..99f78764358 100644 --- a/packages/web-components/fast-foundation/src/progress-ring/index.ts +++ b/packages/web-components/fast-foundation/src/progress-ring/index.ts @@ -1,3 +1,6 @@ export { FASTProgressRing } from "./progress-ring.js"; export { ProgressRingOptions } from "./progress-ring.options.js"; -export { progressRingTemplate } from "./progress-ring.template.js"; +export { + progressRingIndicatorTemplate, + progressRingTemplate, +} from "./progress-ring.template.js"; diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts index 8b6169ec1e4..a155cdb83d1 100644 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts +++ b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts @@ -6,5 +6,6 @@ import type { FASTProgressRing } from "./progress-ring.js"; * @public */ export type ProgressRingOptions = { + determinateIndicator?: StaticallyComposableHTML; indeterminateIndicator?: StaticallyComposableHTML; }; diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts index 11822e01975..291adb73ad9 100644 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts +++ b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts @@ -1,6 +1,7 @@ import { expect, test } from "@playwright/test"; import type { Locator, Page } from "@playwright/test"; import { fixtureURL } from "../__test__/helpers.js"; +import type { FASTProgressRing } from "./progress-ring.js"; test.describe("Progress ring", () => { let page: Page; @@ -61,15 +62,67 @@ test.describe("Progress ring", () => { await expect(element).toHaveAttribute("aria-valuemax", "75"); }); - test("should render an element with a `determinate` slot when a value is provided", async () => { + test("should render an element with a `determinate` class when a value is provided", async () => { await root.evaluate(node => { node.innerHTML = /* html */ ` `; }); - const progress = element.locator(".progress"); + const progress = element.locator(".determinate"); - await expect(progress).toHaveAttribute("slot", "determinate"); + await expect(progress).toHaveCount(1); + }); + + test("should render an element with an `indeterminate` class when no value is provided", async () => { + await root.evaluate(node => { + node.innerHTML = /* html */ ` + + `; + }); + + const progress = element.locator(".indeterminate"); + + await expect(progress).toHaveCount(1); + }); + + test("should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset", async () => { + await page.setContent(/* html */ ` + + `); + + await expect(element).toHaveJSProperty("percentComplete", 50); + }); + + test("should set the `percentComplete` property to match the current `value` in the range of `min` and `max`", async () => { + await page.setContent(/* html */ ` + + `); + + await expect(element).toHaveJSProperty("percentComplete", 0); + + await element.evaluate((node: FASTProgressRing) => { + node.value = 50; + }); + + await expect(element).toHaveJSProperty("percentComplete", 50); + + await element.evaluate((node: FASTProgressRing) => { + node.value = 100; + }); + + await expect(element).toHaveJSProperty("percentComplete", 100); + + await element.evaluate((node: FASTProgressRing) => { + node.max = 200; + }); + + await expect(element).toHaveJSProperty("percentComplete", 50); + + await element.evaluate((node: FASTProgressRing) => { + node.min = 100; + }); + + await expect(element).toHaveJSProperty("percentComplete", 0); }); }); diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts index 05ef4592a35..d4d20789e26 100644 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts +++ b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts @@ -4,7 +4,16 @@ import { staticallyCompose } from "../utilities/template-helpers.js"; import type { FASTProgressRing } from "./progress-ring.js"; import type { ProgressRingOptions } from "./progress-ring.options.js"; -const progressSegments: number = 44; +/** + * The default template for the indicator element of the {@link @microsoft/fast-foundation#FASTProgressRing} component. + * @public + */ +export const progressRingIndicatorTemplate = html` + + + + +`; /** * The template for the {@link @microsoft/fast-foundation#FASTProgressRing} component. @@ -23,35 +32,22 @@ export function progressRingTemplate( ${when( x => typeof x.value === "number", html` - - - - + + ${staticallyCompose(options.determinateIndicator)} + + `, html` - - ${staticallyCompose(options.indeterminateIndicator)} - + + + ${staticallyCompose(options.indeterminateIndicator)} + + ` )} diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts index f3736588496..c88bde8d64b 100644 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts +++ b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts @@ -1,14 +1,13 @@ import { FASTBaseProgress } from "../progress/base-progress.js"; /** - * An circular Progress HTML Element. + * A circular Progress HTML Element. * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#progressbar | ARIA progressbar }. * - * @slot indeterminate - The slot for a custom indeterminate indicator - * @slot determinate - The slot for a custom determinate indicator - * @csspart progress - Represents the progress element + * @slot determinate - The slot for the determinate indicator + * @slot indeterminate - The slot for the indeterminate indicator * @csspart determinate - The determinate indicator - * @csspart background - The background + * @csspart indeterminate - The indeterminate indicator * * @public */ diff --git a/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts b/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts index b7a3cd31f8b..69bfe9183d1 100644 --- a/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts +++ b/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts @@ -1,7 +1,9 @@ -import { html } from "@microsoft/fast-element"; import { css } from "@microsoft/fast-element"; import { FASTProgressRing } from "../progress-ring.js"; -import { progressRingTemplate } from "../progress-ring.template.js"; +import { + progressRingIndicatorTemplate, + progressRingTemplate, +} from "../progress-ring.template.js"; const styles = css` :host { @@ -24,9 +26,14 @@ const styles = css` stroke-width: 2px; } - .determinate { + .determinate .indicator { + --progress-segments: 44; stroke: var(--accent-foreground-rest); fill: none; + stroke-dasharray: calc( + ((var(--progress-segments) * var(--percent-complete)) / 100) * 1px + ) + calc(var(--progress-segments) * 1px); stroke-width: 2px; stroke-linecap: round; transform-origin: 50% 50%; @@ -34,7 +41,7 @@ const styles = css` transition: all 0.2s ease-in-out; } - .indeterminate-indicator-1 { + .indeterminate .indicator { stroke: var(--accent-foreground-rest); fill: none; stroke-width: 2px; @@ -64,24 +71,8 @@ const styles = css` FASTProgressRing.define({ name: "fast-progress-ring", template: progressRingTemplate({ - indeterminateIndicator: /* html */ html` - - - - - `, + determinateIndicator: progressRingIndicatorTemplate, + indeterminateIndicator: progressRingIndicatorTemplate, }), styles, }); diff --git a/packages/web-components/fast-foundation/src/progress/README.md b/packages/web-components/fast-foundation/src/progress/README.md index f34be4523a2..4de218209c2 100644 --- a/packages/web-components/fast-foundation/src/progress/README.md +++ b/packages/web-components/fast-foundation/src/progress/README.md @@ -3,7 +3,7 @@ id: progress title: fast-progress sidebar_label: progress custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/progress/README.md -description: fast-progress is a web component used to display the length of time a process will take or to visualize percentage value. +description: fast-progress is used to display the length of time a process will take or to visualize percentage value or to represent an unspecified wait time. --- *Progress* and *progress ring* are used to display the length of time a process will take or to visualize percentage value (referred to as a **determinate** state) and to represent an unspecified wait time (referred to as an **indeterminate** state). *Progress* components are typically visually represented by a circular or linear animation. When the `value` attribute is passed the state is **determinate**, otherwise it is **indeterminate**. @@ -40,8 +40,7 @@ import { provideFASTDesignSystem() .register( fastProgress({ - indeterminateIndicator1: `...your indeterminate indicator...`, - indeterminateIndicator2: `...your indeterminate indicator...` + indeterminateIndicator: `...your indeterminate indicator...` }), fastProgressRing({ indeterminateIndicator: `...your indeterminate indicator...` @@ -79,8 +78,7 @@ export const myProgress = Progress.compose({ baseName: "progress", template, styles, - indeterminateIndicator1: `...default indeterminate indicator...`, - indeterminateIndicator2: `...default indeterminate indicator...`, + indeterminateIndicator: `...default indeterminate indicator...`, }); ``` @@ -174,17 +172,17 @@ export const myProgressRing = ProgressRing.compose({ #### CSS Parts -| Name | Description | -| --------------- | ------------------------------- | -| `progress` | Represents the progress element | -| `determinate` | The determinate indicator | -| `indeterminate` | The indeterminate indicator | +| Name | Description | +| --------------- | --------------------------- | +| `determinate` | The determinate indicator | +| `indeterminate` | The indeterminate indicator | #### Slots -| Name | Description | -| --------------- | --------------------------------------------- | -| `indeterminate` | The slot for a custom indeterminate indicator | +| Name | Description | +| --------------- | ---------------------------------------- | +| `determinate` | The slot for the determinate indicator | +| `indeterminate` | The slot for the indeterminate indicator |
diff --git a/packages/web-components/fast-foundation/src/progress/index.ts b/packages/web-components/fast-foundation/src/progress/index.ts index 37bedac77c6..4c8a3c5629d 100644 --- a/packages/web-components/fast-foundation/src/progress/index.ts +++ b/packages/web-components/fast-foundation/src/progress/index.ts @@ -1,4 +1,4 @@ export { FASTBaseProgress } from "./base-progress.js"; export { FASTProgress } from "./progress.js"; export { ProgressOptions } from "./progress.options.js"; -export { progressTemplate } from "./progress.template.js"; +export { progressIndicatorTemplate, progressTemplate } from "./progress.template.js"; diff --git a/packages/web-components/fast-foundation/src/progress/progress.options.ts b/packages/web-components/fast-foundation/src/progress/progress.options.ts index 6abd26ba064..9c8af4a838b 100644 --- a/packages/web-components/fast-foundation/src/progress/progress.options.ts +++ b/packages/web-components/fast-foundation/src/progress/progress.options.ts @@ -6,6 +6,6 @@ import type { FASTProgress } from "./progress.js"; * @public */ export type ProgressOptions = { - indeterminateIndicator1?: StaticallyComposableHTML; - indeterminateIndicator2?: StaticallyComposableHTML; + determinateIndicator?: StaticallyComposableHTML; + indeterminateIndicator?: StaticallyComposableHTML; }; diff --git a/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts b/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts index 6e18d38ac55..47be8e1a97a 100644 --- a/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts +++ b/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts @@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test"; import { fixtureURL } from "../__test__/helpers.js"; import type { FASTProgress } from "./progress.js"; -test.describe("Progress ring", () => { +test.describe("Progress", () => { let page: Page; let element: Locator; let root: Locator; @@ -56,28 +56,28 @@ test.describe("Progress ring", () => { await expect(element).toHaveAttribute("aria-valuemax", "50"); }); - test("should render an element with a `determinate` slot when a value is provided", async () => { + test("should render an element with a `determinate` class when a value is provided", async () => { await root.evaluate(node => { node.innerHTML = /* html */ ` `; }); - const progress = element.locator(".progress"); + const progress = element.locator(".determinate"); - await expect(progress).toHaveAttribute("slot", "determinate"); + await expect(progress).toHaveCount(1); }); - test("should render an element with an `indeterminate` slot when no value is provided", async () => { + test("should render an element with an `indeterminate` class when no value is provided", async () => { await root.evaluate(node => { node.innerHTML = /* html */ ` `; }); - const progress = element.locator(".progress"); + const progress = element.locator(".indeterminate"); - await expect(progress).toHaveAttribute("slot", "indeterminate"); + await expect(progress).toHaveCount(1); }); test("should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset", async () => { diff --git a/packages/web-components/fast-foundation/src/progress/progress.template.ts b/packages/web-components/fast-foundation/src/progress/progress.template.ts index 281df7e195d..50be818559c 100644 --- a/packages/web-components/fast-foundation/src/progress/progress.template.ts +++ b/packages/web-components/fast-foundation/src/progress/progress.template.ts @@ -4,6 +4,14 @@ import { staticallyCompose } from "../utilities/template-helpers.js"; import type { FASTProgress } from "./progress.js"; import type { ProgressOptions } from "./progress.options.js"; +/** + * The default template for the indicator element of the {@link @microsoft/fast-foundation#FASTProgress} component. + * @public + */ +export const progressIndicatorTemplate = html` +
+`; + /** * The template for the {@link @microsoft/fast-foundation#FASTProgress} component. * @public @@ -11,7 +19,7 @@ import type { ProgressOptions } from "./progress.options.js"; export function progressTemplate( options: ProgressOptions = {} ): ElementViewTemplate { - return html` + return html` diff --git a/packages/web-components/fast-foundation/src/progress/progress.ts b/packages/web-components/fast-foundation/src/progress/progress.ts index 661b67cb366..4f68e8efac6 100644 --- a/packages/web-components/fast-foundation/src/progress/progress.ts +++ b/packages/web-components/fast-foundation/src/progress/progress.ts @@ -1,11 +1,11 @@ import { FASTBaseProgress } from "./base-progress.js"; /** - * An Progress HTML Element. + * A Progress HTML Element. * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#progressbar | ARIA progressbar }. * - * @slot indeterminate - The slot for a custom indeterminate indicator - * @csspart progress - Represents the progress element + * @slot determinate - The slot for the determinate indicator + * @slot indeterminate - The slot for the indeterminate indicator * @csspart determinate - The determinate indicator * @csspart indeterminate - The indeterminate indicator * diff --git a/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts b/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts index 78e4c909bb9..ee77a4e29e3 100644 --- a/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts +++ b/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts @@ -1,7 +1,6 @@ -import { html } from "@microsoft/fast-element"; import { css } from "@microsoft/fast-element"; import { FASTProgress } from "../progress.js"; -import { progressTemplate } from "../progress.template.js"; +import { progressIndicatorTemplate, progressTemplate } from "../progress.template.js"; const styles = css` :host { @@ -11,15 +10,8 @@ const styles = css` outline: none; height: calc(var(--design-unit) * 1px); margin: calc(var(--design-unit) * 1px) 0; - } - - .progress { background-color: var(--neutral-fill-rest); border-radius: calc(var(--design-unit) * 1px); - width: 100%; - height: 100%; - display: flex; - align-items: center; position: relative; } @@ -29,6 +21,7 @@ const styles = css` height: 100%; transition: all 0.2s ease-in-out; display: flex; + width: calc(var(--percent-complete) * 1%); } .indeterminate { @@ -40,8 +33,8 @@ const styles = css` width: 100%; } - .indeterminate-indicator-1 { - animation: indeterminate-1 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + .indeterminate .indicator { + animation: indeterminate 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; background-color: var(--accent-foreground-rest); border-radius: calc(var(--design-unit) * 1px); height: 100%; @@ -50,17 +43,7 @@ const styles = css` width: 40%; } - .indeterminate-indicator-2 { - position: absolute; - opacity: 0; - height: 100%; - background-color: var(--accent-foreground-rest); - border-radius: calc(var(--design-unit) * 1px); - width: 60%; - animation: indeterminate-2 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; - } - - @keyframes indeterminate-1 { + @keyframes indeterminate { 0% { opacity: 1; transform: translateX(-100%); @@ -77,41 +60,13 @@ const styles = css` transform: translateX(300%); } } - - @keyframes indeterminate-2 { - 0% { - opacity: 0; - transform: translateX(-150%); - } - 29.99% { - opacity: 0; - } - 30% { - opacity: 1; - transform: translateX(-150%); - } - 100% { - transform: translateX(166.66%); - opacity: 1; - } - } `; FASTProgress.define({ name: "fast-progress", template: progressTemplate({ - indeterminateIndicator1: /* html */ html` - - `, - indeterminateIndicator2: /* html */ html` - - `, + determinateIndicator: progressIndicatorTemplate, + indeterminateIndicator: progressIndicatorTemplate, }), styles, });