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

feat(web-components): refactor progress bar to use ElementInternals #31652

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
chrisdholt marked this conversation as resolved.
Show resolved Hide resolved
"type": "prerelease",
"comment": "refactor progress bar to use ElementInternals",
"packageName": "@fluentui/web-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
30 changes: 20 additions & 10 deletions packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -1888,7 +1888,6 @@ export function display(displayValue: CSSDisplayPropertyValue): string;
//
// @public
export class Divider extends FASTElement {
constructor();
// (undocumented)
alignContent?: DividerAlignContent;
// (undocumented)
Expand Down Expand Up @@ -2437,13 +2436,30 @@ export const MenuStyles: ElementStyles;
// @public (undocumented)
export const MenuTemplate: ElementViewTemplate<Menu>;

// Warning: (ae-forgotten-export) The symbol "BaseProgress" needs to be exported by the entry point index.d.ts
//
// @public
export class ProgressBar extends BaseProgress {
export class ProgressBar extends FASTElement {
constructor();
// (undocumented)
connectedCallback(): void;
// @internal
elementInternals: ElementInternals;
// @internal
max?: number;
// (undocumented)
protected maxChanged(): void;
// @internal
min?: number;
// (undocumented)
protected minChanged(): void;
// @internal
percentComplete: number;
shape?: ProgressBarShape;
thickness?: ProgressBarThickness;
validationState: ProgressBarValidationState | null;
// @internal
value?: number | null;
// (undocumented)
protected valueChanged(): void;
}

// @public
Expand Down Expand Up @@ -2485,12 +2501,6 @@ export const ProgressBarValidationState: {
// @public
export type ProgressBarValidationState = ValuesOf<typeof ProgressBarValidationState>;

// @public
export type ProgressOptions = {
indeterminateIndicator1?: StaticallyComposableHTML<ProgressBar>;
indeterminateIndicator2?: StaticallyComposableHTML<ProgressBar>;
};

// Warning: (ae-forgotten-export) The symbol "FormAssociatedRadio" needs to be exported by the entry point index.d.ts
//
// @public
Expand Down
1 change: 0 additions & 1 deletion packages/web-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ export {
ProgressBarThickness,
ProgressBarValidationState,
} from './progress-bar/index.js';
export type { ProgressOptions } from './progress-bar/index.js';
export {
RadioGroup,
RadioGroupDefinition,
Expand Down
71 changes: 0 additions & 71 deletions packages/web-components/src/progress-bar/base-progress.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/web-components/src/progress-bar/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export { definition as ProgressBarDefinition } from './progress-bar.definition.js';
export { ProgressBar } from './progress-bar.js';
export { ProgressBarShape, ProgressBarThickness, ProgressBarValidationState } from './progress-bar.options.js';
export type { ProgressOptions } from './progress-bar.options.js';
export { styles as ProgressBarStyles } from './progress-bar.styles.js';
export { template as ProgressBarTemplate } from './progress-bar.template.js';
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,3 @@ export const ProgressBarValidationState = {
* @public
*/
export type ProgressBarValidationState = ValuesOf<typeof ProgressBarValidationState>;

/**
* Progress configuration options
* @public
*/
export type ProgressOptions = {
indeterminateIndicator1?: StaticallyComposableHTML<ProgressBar>;
indeterminateIndicator2?: StaticallyComposableHTML<ProgressBar>;
};
123 changes: 48 additions & 75 deletions packages/web-components/src/progress-bar/progress-bar.spec.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,70 @@
import { expect, test } from '@playwright/test';
import type { Locator, Page } from '@playwright/test';
import { fixtureURL } from '../helpers.tests.js';
import type { ProgressBar } from './progress-bar.js';

test.describe('Progress Bar', () => {
let page: Page;
let element: Locator;
let root: Locator;

test.beforeAll(async ({ browser }) => {
page = await browser.newPage();

element = page.locator('fluent-progress-bar');

root = page.locator('#root');

test.beforeEach(async ({ page }) => {
await page.goto(fixtureURL('components-progressbar--progress'));
});

test.afterAll(async () => {
await page.close();
await page.waitForFunction(() => customElements.whenDefined('fluent-progress-bar'));
});

// Foundation tests
test('should include a role of progressbar', async () => {
await expect(element).toHaveAttribute('role', 'progressbar');
});
test('should include a role of progressbar', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

test('should set the `aria-valuenow` attribute with the `value` property when provided', async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar value="50"></fluent-progress-bar>
`;
});

await expect(element).toHaveAttribute('aria-valuenow', '50');
await expect(element).toHaveJSProperty('elementInternals.role', 'progressbar');
});

test('should set the `aria-valuemin` attribute with the `min` property when provided', async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar min="50"></fluent-progress-bar>
`;
});
test('should set the `aria-valuenow` attribute with the `value` property when provided', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

await expect(element).toHaveAttribute('aria-valuemin', '50');
});
await page.setContent(/* html */ `
<fluent-progress-bar value="50"></fluent-progress-bar>
`);

test('should set the `aria-valuemax` attribute with the `max` property when provided', async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar max="50"></fluent-progress-bar>
`;
});

await expect(element).toHaveAttribute('aria-valuemax', '50');
await expect(element).toHaveJSProperty('elementInternals.ariaValueNow', '50');
});

test('should render an element with a `determinate` slot when a value is provided', async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar value="50"></fluent-progress-bar>
`;
});
test('should set the `aria-valuemin` attribute with the `min` property when provided', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

const progress = element.locator('.progress');
await page.setContent(/* html */ `
<fluent-progress-bar min="50"></fluent-progress-bar>
`);

await expect(progress).toHaveAttribute('slot', 'determinate');
await expect(element).toHaveJSProperty('elementInternals.ariaValueMin', '50');
});

test('should render an element with an `indeterminate` slot when no value is provided', async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar></fluent-progress-bar>
`;
});
test('should set the `aria-valuemax` attribute with the `max` property when provided', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

const progress = element.locator('.progress');
await page.setContent(/* html */ `
<fluent-progress-bar max="50"></fluent-progress-bar>
`);

await expect(progress).toHaveAttribute('slot', 'indeterminate');
await expect(element).toHaveJSProperty('elementInternals.ariaValueMax', '50');
});

test('should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset', async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar value="50"></fluent-progress-bar>
`;
});
test('should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset', async ({
page,
}) => {
const element = page.locator('fluent-progress-bar');

await page.setContent(/* html */ `
<fluent-progress-bar value="50"></fluent-progress-bar>
`);

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 root.evaluate(node => {
node.innerHTML = /* html */ `
<fluent-progress-bar value="0"></fluent-progress-bar>
`;
});
test('should set the `percentComplete` property to match the current `value` in the range of `min` and `max`', async ({
page,
}) => {
const element = page.locator('fluent-progress-bar');

await page.setContent(/* html */ `
<fluent-progress-bar value="0"></fluent-progress-bar>
`);

await expect(element).toHaveJSProperty('percentComplete', 0);

Expand Down Expand Up @@ -125,8 +93,9 @@ test.describe('Progress Bar', () => {
await expect(element).toHaveJSProperty('percentComplete', 0);
});

// Fluent Specific propertiy tests
test('should set and retrieve the `thickness` property correctly', async () => {
test('should set and retrieve the `thickness` property correctly', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

await element.evaluate((node: ProgressBar) => {
node.thickness = 'medium';
});
Expand All @@ -140,7 +109,9 @@ test.describe('Progress Bar', () => {
await expect(element).toHaveJSProperty('thickness', 'large');
});

test('should set and retrieve the `shape` property correctly', async () => {
test('should set and retrieve the `shape` property correctly', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

await element.evaluate((node: ProgressBar) => {
node.shape = 'square';
});
Expand All @@ -154,7 +125,9 @@ test.describe('Progress Bar', () => {
await expect(element).toHaveJSProperty('shape', 'rounded');
});

test('should set and retrieve the `validationState` property correctly', async () => {
test('should set and retrieve the `validationState` property correctly', async ({ page }) => {
const element = page.locator('fluent-progress-bar');

await element.evaluate((node: ProgressBar) => {
node.validationState = 'success';
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ const storyTemplate = html<ProgressStoryArgs>`
thickness=${x => x.thickness}
shape=${x => x.shape}
max=${x => x.max}
aria-valuemax=${x => x.max}
aria-valuenow=${x => x.value}
min=${x => x.min}
value=${x => x.value}
validation-state=${x => x.validationState}
></fluent-progress-bar>
Expand Down Expand Up @@ -72,26 +71,26 @@ export const Max = renderComponent(html<ProgressStoryArgs>`
<div>
<p>
<code>3 of 10</code>
<fluent-progress-bar value="3" aria-valuenow="3" max="10" aria-valuemax="10"></fluent-progress-bar>
<fluent-progress-bar value="3" max="10"></fluent-progress-bar>
</p>
<p>
<code>3 o 5</code>
<fluent-progress-bar value="3" aria-valuenow="3" max="5" aria-valuemax="5"></fluent-progress-bar>
<code>3 of 5</code>
<fluent-progress-bar value="3" max="5"></fluent-progress-bar>
</p>
</div>
`);

export const Value = renderComponent(html<ProgressStoryArgs>`
<div>
<code>0</code><fluent-progress-bar value="0" aria-valuenow="0"></fluent-progress-bar>
<code>0</code><fluent-progress-bar value="0"></fluent-progress-bar>
<code>25</code>
<fluent-progress-bar value="25" aria-valuenow="25"></fluent-progress-bar>
<fluent-progress-bar value="25"></fluent-progress-bar>
<code>50</code>
<fluent-progress-bar value="50" aria-valuenow="50"></fluent-progress-bar>
<fluent-progress-bar value="50"></fluent-progress-bar>
<code>75</code>
<fluent-progress-bar value="75" aria-valuenow="75"></fluent-progress-bar>
<fluent-progress-bar value="75"></fluent-progress-bar>
<code>100</code>
<fluent-progress-bar value="100" aria-valuenow="100"></fluent-progress-bar>
<fluent-progress-bar value="100"></fluent-progress-bar>
</div>
`);

Expand Down
Loading
Loading