feat(progress-bar): add styling for the ionic theme (#30185)
Issue number: internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? ion-progress-bar does not currently have any custom styling for the ionic theme. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> According to the design, the following styling changes were made: - Added a new shape prop which controls the shape of the progress bar - Changed the color of the unfilled part of the progress bar and the bar height to design token values - Adding a new testing page and screenshot tests ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. -->
@ -1661,6 +1661,7 @@ ion-progress-bar,prop,buffer,number,1,false,false
|
|||||||
ion-progress-bar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
ion-progress-bar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||||
ion-progress-bar,prop,mode,"ios" | "md",undefined,false,false
|
ion-progress-bar,prop,mode,"ios" | "md",undefined,false,false
|
||||||
ion-progress-bar,prop,reversed,boolean,false,false,false
|
ion-progress-bar,prop,reversed,boolean,false,false,false
|
||||||
|
ion-progress-bar,prop,shape,"rectangular" | "round" | undefined,undefined,false,false
|
||||||
ion-progress-bar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
ion-progress-bar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||||
ion-progress-bar,prop,type,"determinate" | "indeterminate",'determinate',false,false
|
ion-progress-bar,prop,type,"determinate" | "indeterminate",'determinate',false,false
|
||||||
ion-progress-bar,prop,value,number,0,false,false
|
ion-progress-bar,prop,value,number,0,false,false
|
||||||
|
8
core/src/components.d.ts
vendored
@ -2609,6 +2609,10 @@ export namespace Components {
|
|||||||
* If true, reverse the progress bar direction.
|
* If true, reverse the progress bar direction.
|
||||||
*/
|
*/
|
||||||
"reversed": boolean;
|
"reversed": boolean;
|
||||||
|
/**
|
||||||
|
* Set to `"round"` for a progress bar with rounded corners, or `"rectangular"` for a progress bar without rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
|
||||||
|
*/
|
||||||
|
"shape"?: 'round' | 'rectangular';
|
||||||
/**
|
/**
|
||||||
* The theme determines the visual appearance of the component.
|
* The theme determines the visual appearance of the component.
|
||||||
*/
|
*/
|
||||||
@ -7959,6 +7963,10 @@ declare namespace LocalJSX {
|
|||||||
* If true, reverse the progress bar direction.
|
* If true, reverse the progress bar direction.
|
||||||
*/
|
*/
|
||||||
"reversed"?: boolean;
|
"reversed"?: boolean;
|
||||||
|
/**
|
||||||
|
* Set to `"round"` for a progress bar with rounded corners, or `"rectangular"` for a progress bar without rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
|
||||||
|
*/
|
||||||
|
"shape"?: 'round' | 'rectangular';
|
||||||
/**
|
/**
|
||||||
* The theme determines the visual appearance of the component.
|
* The theme determines the visual appearance of the component.
|
||||||
*/
|
*/
|
||||||
|
22
core/src/components/progress-bar/progress-bar.ionic.scss
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
@use "../../themes/ionic/ionic.globals.scss" as globals;
|
||||||
|
@use "./progress-bar";
|
||||||
|
|
||||||
|
// Ionic Progress bar
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
:host {
|
||||||
|
--background: #{globals.$ion-bg-neutral-subtle-default};
|
||||||
|
|
||||||
|
height: globals.$ion-scale-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress Bar Shapes
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
:host(.progress-bar-shape-round) {
|
||||||
|
@include globals.border-radius(globals.$ion-round-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.progress-bar-shape-rectangular) {
|
||||||
|
@include globals.border-radius(globals.$ion-rectangular-xs);
|
||||||
|
}
|
@ -21,7 +21,7 @@ import type { Color } from '../../interface';
|
|||||||
styleUrls: {
|
styleUrls: {
|
||||||
ios: 'progress-bar.ios.scss',
|
ios: 'progress-bar.ios.scss',
|
||||||
md: 'progress-bar.md.scss',
|
md: 'progress-bar.md.scss',
|
||||||
ionic: 'progress-bar.md.scss',
|
ionic: 'progress-bar.ionic.scss',
|
||||||
},
|
},
|
||||||
shadow: true,
|
shadow: true,
|
||||||
})
|
})
|
||||||
@ -57,10 +57,35 @@ export class ProgressBar implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop({ reflect: true }) color?: Color;
|
@Prop({ reflect: true }) color?: Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to `"round"` for a progress bar with rounded corners, or `"rectangular"`
|
||||||
|
* for a progress bar without rounded corners.
|
||||||
|
*
|
||||||
|
* Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
|
||||||
|
*/
|
||||||
|
@Prop() shape?: 'round' | 'rectangular';
|
||||||
|
|
||||||
|
private getShape(): string | undefined {
|
||||||
|
const theme = getIonTheme(this);
|
||||||
|
const { shape } = this;
|
||||||
|
|
||||||
|
// TODO(ROU-11638): Remove theme check when shapes are defined for all themes.
|
||||||
|
if (theme !== 'ionic') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape === undefined) {
|
||||||
|
return 'round';
|
||||||
|
}
|
||||||
|
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { color, type, reversed, value, buffer } = this;
|
const { color, type, reversed, value, buffer } = this;
|
||||||
const paused = config.getBoolean('_testing');
|
const paused = config.getBoolean('_testing');
|
||||||
const theme = getIonTheme(this);
|
const theme = getIonTheme(this);
|
||||||
|
const shape = this.getShape();
|
||||||
// If the progress is displayed as a solid bar.
|
// If the progress is displayed as a solid bar.
|
||||||
const progressSolid = buffer === 1;
|
const progressSolid = buffer === 1;
|
||||||
return (
|
return (
|
||||||
@ -75,6 +100,7 @@ export class ProgressBar implements ComponentInterface {
|
|||||||
'progress-paused': paused,
|
'progress-paused': paused,
|
||||||
'progress-bar-reversed': document.dir === 'rtl' ? !reversed : reversed,
|
'progress-bar-reversed': document.dir === 'rtl' ? !reversed : reversed,
|
||||||
'progress-bar-solid': progressSolid,
|
'progress-bar-solid': progressSolid,
|
||||||
|
[`progress-bar-shape-${shape}`]: shape !== undefined,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{type === 'indeterminate' ? renderIndeterminate() : renderProgress(value, buffer)}
|
{type === 'indeterminate' ? renderIndeterminate() : renderProgress(value, buffer)}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { expect } from '@playwright/test';
|
import { expect } from '@playwright/test';
|
||||||
import { configs, test } from '@utils/test/playwright';
|
import { configs, test } from '@utils/test/playwright';
|
||||||
|
|
||||||
configs().forEach(({ title, screenshot, config }) => {
|
configs({ modes: ['ios', 'md', 'ionic-md'] }).forEach(({ title, screenshot, config }) => {
|
||||||
test.describe(title('progress-bar: basic'), () => {
|
test.describe(title('progress-bar: basic'), () => {
|
||||||
test('should not have visual regressions', async ({ page }) => {
|
test('should not have visual regressions', async ({ page }) => {
|
||||||
await page.goto('/src/components/progress-bar/test/basic', config);
|
await page.goto('/src/components/progress-bar/test/basic', config);
|
||||||
|
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 26 KiB |
51
core/src/components/progress-bar/test/shape/index.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Progress Bar - Shape</title>
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||||
|
/>
|
||||||
|
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||||
|
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||||
|
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||||
|
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||||
|
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<ion-app>
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title>Progress Bar - Shape</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-list lines="none">
|
||||||
|
<ion-list-header>
|
||||||
|
<ion-label> Default </ion-label>
|
||||||
|
</ion-list-header>
|
||||||
|
<ion-item>
|
||||||
|
<ion-progress-bar value="0.50"></ion-progress-bar>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-list-header>
|
||||||
|
<ion-label> Round </ion-label>
|
||||||
|
</ion-list-header>
|
||||||
|
<ion-item>
|
||||||
|
<ion-progress-bar value="0.50" shape="round"></ion-progress-bar>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-list-header>
|
||||||
|
<ion-label> Rectangular </ion-label>
|
||||||
|
</ion-list-header>
|
||||||
|
<ion-item>
|
||||||
|
<ion-progress-bar value="0.50" shape="rectangular"></ion-progress-bar>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-content>
|
||||||
|
</ion-app>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,56 @@
|
|||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { configs, test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
|
||||||
|
test.describe(title('progress-bar: shape'), () => {
|
||||||
|
test('round - should not have visual regressions', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
background: #ccc7c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<ion-progress-bar value="0.50" shape="round"></ion-progress-bar>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const container = page.locator('.container');
|
||||||
|
|
||||||
|
await expect(container).toHaveScreenshot(screenshot(`progress-bar-shape-round`));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rectangular - should not have visual regressions', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
background: #ccc7c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<ion-progress-bar value="0.50" shape="rectangular"></ion-progress-bar>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const container = page.locator('.container');
|
||||||
|
|
||||||
|
await expect(container).toHaveScreenshot(screenshot(`progress-bar-shape-rectangular`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 219 B |
After Width: | Height: | Size: 386 B |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 264 B |
After Width: | Height: | Size: 452 B |
After Width: | Height: | Size: 271 B |
@ -1589,14 +1589,14 @@ Shorthand for ionPickerDidDismiss.
|
|||||||
|
|
||||||
|
|
||||||
@ProxyCmp({
|
@ProxyCmp({
|
||||||
inputs: ['buffer', 'color', 'mode', 'reversed', 'theme', 'type', 'value']
|
inputs: ['buffer', 'color', 'mode', 'reversed', 'shape', 'theme', 'type', 'value']
|
||||||
})
|
})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-progress-bar',
|
selector: 'ion-progress-bar',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: '<ng-content></ng-content>',
|
template: '<ng-content></ng-content>',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['buffer', 'color', 'mode', 'reversed', 'theme', 'type', 'value'],
|
inputs: ['buffer', 'color', 'mode', 'reversed', 'shape', 'theme', 'type', 'value'],
|
||||||
})
|
})
|
||||||
export class IonProgressBar {
|
export class IonProgressBar {
|
||||||
protected el: HTMLElement;
|
protected el: HTMLElement;
|
||||||
|
@ -1593,14 +1593,14 @@ Shorthand for ionPickerDidDismiss.
|
|||||||
|
|
||||||
@ProxyCmp({
|
@ProxyCmp({
|
||||||
defineCustomElementFn: defineIonProgressBar,
|
defineCustomElementFn: defineIonProgressBar,
|
||||||
inputs: ['buffer', 'color', 'mode', 'reversed', 'theme', 'type', 'value']
|
inputs: ['buffer', 'color', 'mode', 'reversed', 'shape', 'theme', 'type', 'value']
|
||||||
})
|
})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-progress-bar',
|
selector: 'ion-progress-bar',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: '<ng-content></ng-content>',
|
template: '<ng-content></ng-content>',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['buffer', 'color', 'mode', 'reversed', 'theme', 'type', 'value'],
|
inputs: ['buffer', 'color', 'mode', 'reversed', 'shape', 'theme', 'type', 'value'],
|
||||||
standalone: true
|
standalone: true
|
||||||
})
|
})
|
||||||
export class IonProgressBar {
|
export class IonProgressBar {
|
||||||
|
@ -619,7 +619,8 @@ export const IonProgressBar = /*@__PURE__*/ defineContainer<JSX.IonProgressBar>(
|
|||||||
'reversed',
|
'reversed',
|
||||||
'value',
|
'value',
|
||||||
'buffer',
|
'buffer',
|
||||||
'color'
|
'color',
|
||||||
|
'shape'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|