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

refactor(progressbar): Animate the value change using CSS counters and custom CSS props #1492

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
630b655
refactor(linear-progressbar): Use css counter and transition for anim…
desig9stein Nov 19, 2024
10d55a1
refactor(progressbar): fix indeterminate animations and simplify the …
desig9stein Nov 22, 2024
91f18b8
refactor(progressbar): fix for 0 value
desig9stein Nov 22, 2024
872b0cf
refactor(progressbar): remove css vars from the constructor since the…
desig9stein Nov 22, 2024
c15dfb4
Merge branch 'master' into igniteui-webcomponents-1441
simeonoff Nov 25, 2024
26f4ae4
refactor(progressbar): fix label format not working, rewrite some of …
desig9stein Nov 26, 2024
d9b13d5
refactor(progressbar): optimize the code
desig9stein Dec 2, 2024
b478f1b
refactor(progressbar): cleanup the code
desig9stein Dec 2, 2024
765f2fe
Merge branch 'master' into igniteui-webcomponents-1441
desig9stein Dec 2, 2024
4b464f1
Merge branch 'master' into igniteui-webcomponents-1441
desig9stein Dec 2, 2024
3305513
refactor(progress): Declarative binding of counter styles
rkaraivanov Dec 2, 2024
da8d06c
test(linear-progress): Refactored tests to new structure
rkaraivanov Dec 3, 2024
b4aa760
test(circular-progress): Adjusted tests to new structure
rkaraivanov Dec 3, 2024
fb23b6f
Merge branch 'master' into igniteui-webcomponents-1441
rkaraivanov Dec 5, 2024
e9cddfa
Merge branch 'master' into igniteui-webcomponents-1441
simeonoff Dec 6, 2024
63efd51
Merge branch 'master' into igniteui-webcomponents-1441
rkaraivanov Dec 9, 2024
ee493be
fix(progressbar): fix the rtl animations
desig9stein Dec 10, 2024
57ce47e
fix(progressbar): Add helper function to retrieve easing curves
desig9stein Dec 10, 2024
b07c57e
fix(progressbar): fix circular indeterminate state in rtl and clean u…
desig9stein Dec 11, 2024
ef31822
fix(progressbar): remove base and label placeholders
desig9stein Dec 11, 2024
ea9eda5
fix(progressbar): remove shared file, optimize css output for linear …
desig9stein Dec 11, 2024
85869c8
Merge branch 'master' into igniteui-webcomponents-1441
desig9stein Dec 11, 2024
b40bc18
Merge branch 'master' into igniteui-webcomponents-1441
rkaraivanov Dec 12, 2024
5729adc
Merge branch 'master' into igniteui-webcomponents-1441
simeonoff Dec 13, 2024
f24d816
refactor(progressbar): change [part='svg indeterminate'] selector
desig9stein Dec 13, 2024
c457151
Update src/components/progress/themes/circular/shared/circular.progre…
desig9stein Dec 17, 2024
fc0a436
refactor(progressbar): add comments to clarify why we use px for --st…
desig9stein Dec 17, 2024
051f968
Merge branch 'master' into igniteui-webcomponents-1441
simeonoff Dec 18, 2024
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
150 changes: 64 additions & 86 deletions src/components/progress/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,42 @@ import {
queryAssignedElements,
state,
} from 'lit/decorators.js';

import type { StyleInfo } from 'lit/directives/style-map.js';
import { watch } from '../common/decorators/watch.js';
import { asPercent, clamp, formatString } from '../common/util.js';
import {
asPercent,
clamp,
formatString,
isEmpty,
partNameMap,
} from '../common/util.js';
import type { StyleVariant } from '../types.js';

export abstract class IgcProgressBaseComponent extends LitElement {
private __internals: ElementInternals;
private _ticker!: number;
private readonly __internals: ElementInternals;

@queryAssignedElements()
protected assignedElements!: Array<HTMLElement>;
protected _assignedElements!: HTMLElement[];

@query('[part="base"]', true)
protected _base!: HTMLElement;

@query('[part~="fill"]', true)
protected progressIndicator!: Element;
@state()
protected _percentage = 0;

@state()
protected _progress = 0;

@state()
protected percentage = 0;
protected _hasFraction = false;

@state()
protected progress = 0;
protected _styleInfo: StyleInfo = {
'--_progress-whole': '0.00',
'--_progress-integer': '0',
'--_progress-fraction': '0',
'--_transition-duration': '0ms',
};

/**
* Maximum value of the control.
Expand Down Expand Up @@ -78,49 +94,43 @@ export abstract class IgcProgressBaseComponent extends LitElement {
@property({ attribute: 'label-format' })
public labelFormat!: string;

@watch('indeterminate', { waitUntilFirstUpdate: true })
@watch('indeterminate')
protected indeterminateChange() {
this.cancelAnimations();

if (!this.indeterminate) {
this._setProgress();
this.animateLabelTo(0, this.value);
this._updateProgress();
}
}

@watch('max', { waitUntilFirstUpdate: true })
@watch('max')
protected maxChange() {
this.max = Math.max(0, this.max);

if (this.value > this.max) {
this.value = this.max;
}

this._setProgress();

if (!this.indeterminate) {
cancelAnimationFrame(this._ticker);
this.animateLabelTo(this.max, this.value);
this._updateProgress();
}
}

@watch('value', { waitUntilFirstUpdate: true })
protected valueChange(previous: number) {
@watch('value')
protected valueChange() {
this.value = clamp(this.value, 0, this.max);
this._setProgress();

if (!this.indeterminate) {
cancelAnimationFrame(this._ticker);
this.animateLabelTo(previous, this.value);
this._updateProgress();
}
}

constructor() {
super();
this.__internals = this.attachInternals();

this.__internals.role = 'progressbar';
this.__internals.ariaValueMin = '0';
Object.assign(this.__internals, {
role: 'progressbar',
ariaValueMin: '0',
ariaValueNow: '0',
});
}

protected override createRenderRoot() {
Expand All @@ -134,83 +144,51 @@ export abstract class IgcProgressBaseComponent extends LitElement {
}

private _updateARIA() {
const internals = this.__internals;
const text = this.labelFormat
? this.renderLabelFormat()
: `${this.percentage}%`;

internals.ariaValueMax = `${this.max}`;
internals.ariaValueNow = this.indeterminate ? null : `${this.value}`;
internals.ariaValueText = this.indeterminate ? null : text;
}
const text = this.labelFormat ? this.renderLabelFormat() : `${this.value}%`;

private _setProgress() {
this.progress = this.value / this.max;
Object.assign(this.__internals, {
ariaValueMax: this.max.toString(),
ariaValueNow: this.indeterminate ? null : this.value.toString(),
ariaValueText: this.indeterminate ? null : text,
});
}

public override async connectedCallback() {
super.connectedCallback();
private _updateProgress() {
const percentage = asPercent(this.value, Math.max(1, this.max));
const fractionValue = Math.round((percentage % 1) * 100);
this._hasFraction = fractionValue > 0;

await this.updateComplete;
if (!this.indeterminate) {
requestAnimationFrame(() => {
this._setProgress();
this.animateLabelTo(0, this.value);
});
}
this._styleInfo = {
'--_progress-whole': percentage.toFixed(2),
'--_progress-integer': Math.floor(percentage),
'--_progress-fraction': fractionValue,
'--_transition-duration': `${this.animationDuration}ms`,
};
}

protected cancelAnimations() {
cancelAnimationFrame(this._ticker);
this.progressIndicator?.getAnimations().forEach((animation) => {
if (animation instanceof CSSTransition) {
animation.cancel();
}
protected renderLabel() {
const parts = partNameMap({
label: true,
value: true,
fraction: this._hasFraction,
});
}

protected animateLabelTo(start: number, end: number) {
let t0: number;

const tick = (t1: number) => {
t0 = t0 ?? t1;

const delta = Math.min(
(t1 - t0) / Math.max(this.animationDuration, 1),
1
);

this.percentage = Math.floor(
asPercent(delta * (end - start) + start, this.max)
);

if (delta < 1) {
this._ticker = requestAnimationFrame(tick);
} else {
cancelAnimationFrame(this._ticker);
}
};

requestAnimationFrame(tick);
return this.labelFormat
? html`<span part=${parts}>${this.renderLabelFormat()}</span>`
: html`<span part="${parts} counter"></span>`;
}

protected renderLabelFormat() {
return formatString(this.labelFormat, this.value, this.max);
}

protected renderDefaultSlot() {
const hasNoLabel =
this.indeterminate || this.hideLabel || this.assignedElements.length;
const hideDefaultLabel =
this.indeterminate || this.hideLabel || !isEmpty(this._assignedElements);

return html`
<slot part="label"></slot>
${hasNoLabel
? nothing
: html`<span part="label value">${this.renderLabelText()}</span>`}
${hideDefaultLabel ? nothing : this.renderLabel()}
`;
}

protected renderLabelText() {
return this.labelFormat ? this.renderLabelFormat() : `${this.percentage}%`;
}
}
Loading
Loading