Skip to content

Commit

Permalink
feat: update progress bar to use element internals custom states for …
Browse files Browse the repository at this point in the history
…visual states (#31739)
  • Loading branch information
chrisdholt authored Jun 18, 2024
1 parent 5e700b8 commit 14ff3fa
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat: update progress bar to use element internals custom states for visual states",
"packageName": "@fluentui/web-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
3 changes: 3 additions & 0 deletions packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -2487,8 +2487,11 @@ export class ProgressBar extends FASTElement {
// @internal
get percentComplete(): number;
shape?: ProgressBarShape;
shapeChanged(prev: ProgressBarShape | undefined, next: ProgressBarShape | undefined): void;
thickness?: ProgressBarThickness;
thicknessChanged(prev: ProgressBarThickness | undefined, next: ProgressBarThickness | undefined): void;
validationState: ProgressBarValidationState | null;
validationStateChanged(prev: ProgressBarValidationState | undefined, next: ProgressBarValidationState | undefined): void;
// @internal
value?: number;
// @internal
Expand Down
19 changes: 19 additions & 0 deletions packages/web-components/src/progress-bar/progress-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ test.describe('Progress Bar', () => {
});

await expect(element).toHaveJSProperty('thickness', 'medium');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('medium'))).toBe(true);

await element.evaluate((node: ProgressBar) => {
node.thickness = 'large';
});

await expect(element).toHaveJSProperty('thickness', 'large');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('medium'))).toBe(false);
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('large'))).toBe(true);
});

test('should set and retrieve the `shape` property correctly', async ({ page }) => {
Expand All @@ -117,12 +120,15 @@ test.describe('Progress Bar', () => {
});

await expect(element).toHaveJSProperty('shape', 'square');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('square'))).toBe(true);

await element.evaluate((node: ProgressBar) => {
node.shape = 'rounded';
});

await expect(element).toHaveJSProperty('shape', 'rounded');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('square'))).toBe(false);
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('rounded'))).toBe(true);
});

test('should set and retrieve the `validationState` property correctly', async ({ page }) => {
Expand All @@ -133,17 +139,30 @@ test.describe('Progress Bar', () => {
});

await expect(element).toHaveJSProperty('validationState', 'success');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('success'))).toBe(true);

await element.evaluate((node: ProgressBar) => {
node.validationState = 'warning';
});

await expect(element).toHaveJSProperty('validationState', 'warning');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('success'))).toBe(false);
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('warning'))).toBe(true);

await element.evaluate((node: ProgressBar) => {
node.validationState = 'error';
});

await expect(element).toHaveJSProperty('validationState', 'error');
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('warning'))).toBe(false);
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('error'))).toBe(true);

await element.evaluate((node: ProgressBar) => {
node.validationState = null;
});

expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('success'))).toBe(false);
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('warning'))).toBe(false);
expect(await element.evaluate((node: ProgressBar) => node.elementInternals.states.has('error'))).toBe(false);
});
});
13 changes: 7 additions & 6 deletions packages/web-components/src/progress-bar/progress-bar.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
colorPaletteRedBackground3,
colorTransparentBackground,
} from '../theme/design-tokens.js';
import { errorState, largeState, squareState, successState, warningState } from '../styles/states/index.js';

/** ProgressBar styles
* @public
Expand All @@ -26,11 +27,11 @@ export const styles = css`
contain: content;
}
:host([thickness='large']) {
:host(${largeState}) {
height: 4px;
}
:host([shape='square']) {
:host(${squareState}) {
border-radius: ${borderRadiusNone};
}
Expand Down Expand Up @@ -59,15 +60,15 @@ export const styles = css`
animation-iteration-count: infinite;
}
:host([validation-state='error']) .indicator {
:host(${errorState}) .indicator {
background-color: ${colorPaletteRedBackground3};
}
:host([validation-state='warning']) .indicator {
:host(${warningState}) .indicator {
background-color: ${colorPaletteDarkOrangeBackground3};
}
:host([validation-state='success']) .indicator {
:host(${successState}) .indicator {
background-color: ${colorPaletteGreenBackground3};
}
Expand Down Expand Up @@ -98,7 +99,7 @@ export const styles = css`
background-color: CanvasText;
}
.indicator,
:host(:is([validation-state='success'], [validation-state='warning'], [validation-state='error'])) .indicator {
:host(:is(${successState}, ${warningState}, ${errorState})) .indicator {
background-color: Highlight;
}
`),
Expand Down
46 changes: 46 additions & 0 deletions packages/web-components/src/progress-bar/progress-bar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { attr, FASTElement, nullableNumberConverter, volatile } from '@microsoft/fast-element';
import { toggleState } from '../utils/element-internals.js';
import { ProgressBarShape, ProgressBarThickness, ProgressBarValidationState } from './progress-bar.options.js';

/**
Expand All @@ -24,6 +25,20 @@ export class ProgressBar extends FASTElement {
@attr
public thickness?: ProgressBarThickness;

/**
* Handles changes to thickness attribute custom states
* @param prev - the previous state
* @param next - the next state
*/
public thicknessChanged(prev: ProgressBarThickness | undefined, next: ProgressBarThickness | undefined) {
if (prev) {
toggleState(this.elementInternals, `${prev}`, false);
}
if (next) {
toggleState(this.elementInternals, `${next}`, true);
}
}

/**
* The shape of the progress bar
* @public
Expand All @@ -32,6 +47,20 @@ export class ProgressBar extends FASTElement {
@attr
public shape?: ProgressBarShape;

/**
* Handles changes to shape attribute custom states
* @param prev - the previous state
* @param next - the next state
*/
public shapeChanged(prev: ProgressBarShape | undefined, next: ProgressBarShape | undefined) {
if (prev) {
toggleState(this.elementInternals, `${prev}`, false);
}
if (next) {
toggleState(this.elementInternals, `${next}`, true);
}
}

/**
* The validation state of the progress bar
* @public
Expand All @@ -40,6 +69,23 @@ export class ProgressBar extends FASTElement {
@attr({ attribute: 'validation-state' })
public validationState: ProgressBarValidationState | null = null;

/**
* Handles changes to validation-state attribute custom states
* @param prev - the previous state
* @param next - the next state
*/
public validationStateChanged(
prev: ProgressBarValidationState | undefined,
next: ProgressBarValidationState | undefined,
) {
if (prev) {
toggleState(this.elementInternals, `${prev}`, false);
}
if (next) {
toggleState(this.elementInternals, `${next}`, true);
}
}

/**
* The value of the progress
* @internal
Expand Down
6 changes: 6 additions & 0 deletions packages/web-components/src/styles/states/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ export const pressedState = css.partial`:is([state--pressed], :state(pressed))`;
*/
export const brandState = css.partial`:is([state--brand], :state(brand))`;

/**
* Selector for the `error` state.
* @public
*/
export const errorState = css.partial`:is([state--error], :state(error))`;

/**
* Selector for the `danger` state.
* @public
Expand Down

0 comments on commit 14ff3fa

Please sign in to comment.