feat(progress): add parts for more design customization (#22938)

resolves #20062 fixes #21820
This commit is contained in:
Brandy Carney
2021-03-04 12:48:52 -05:00
committed by GitHub
parent e828a9a693
commit e256d3f09f
6 changed files with 245 additions and 49 deletions

View File

@ -844,6 +844,9 @@ ion-progress-bar,prop,value,number,0,false,false
ion-progress-bar,css-prop,--background
ion-progress-bar,css-prop,--buffer-background
ion-progress-bar,css-prop,--progress-background
ion-progress-bar,part,progress
ion-progress-bar,part,stream
ion-progress-bar,part,track
ion-radio,shadow
ion-radio,prop,color,string | undefined,undefined,false,false

View File

@ -1,18 +1,19 @@
@import "../../themes/ionic.globals";
// Progress bar
// --------------------------------------------------
// Host has no background by default - this will be added to the progress-buffer-bar
// ------------------------------------------------------------------------
// Host has no background by default - this will be added to the progress-buffer-bar
:host {
/**
* @prop --background: Same as --buffer-background when using a determinate progress bar, otherwise it styles the background of the ion-progress-bar itself.
* @prop --progress-background: Color of the progress bar
* @prop --buffer-background: Color of the buffer bar
*/
* @prop --background: Background of the progress track, or the buffer bar if `buffer` is set
* @prop --progress-background: Background of the progress bar representing the current value
* @prop --buffer-background: DEPRECATED, use `--background` instead
*/
--background: #{ion-color(primary, base, 0.3)};
--progress-background: #{ion-color(primary, base)};
--buffer-background: var(--background);
display: block;
position: relative;
@ -25,16 +26,6 @@
overflow: hidden;
}
:host(.ion-color) {
--progress-background: #{current-color(base)};
--buffer-background: #{current-color(base, 0.3)};
}
// indeterminate has no progress-buffer-bar, so it will be added to the host
:host(.progress-bar-indeterminate) {
background: var(--buffer-background);
}
.progress,
.progress-indeterminate,
.indeterminate-bar-primary,
@ -128,27 +119,33 @@
}
}
// Buffer style
// --------------------------------------------------
// Progress Bar: Buffer Circles
// ------------------------------------------------------------------------
.buffer-circles {
background: radial-gradient(ellipse at center, var(--buffer-background) 0%, var(--buffer-background) 30%, transparent 30%) repeat-x 5px center;
background-image: radial-gradient(ellipse at center, var(--buffer-background) 0%, var(--buffer-background) 30%, transparent 30%);
/* stylelint-disable property-blacklist */
background-repeat: repeat-x;
background-position: 5px center;
background-size: 10px 10px;
/* stylelint-enable property-blacklist */
z-index: 0;
animation: buffering 450ms infinite linear;
}
// Progress Bar: Reversed
// ------------------------------------------------------------------------
// If reversed is set to true, the animation will be reversed
// and the bars starting at the top right
// --------------------------------------------------
// and the bar will start at the top right
:host(.progress-bar-reversed) {
transform: scaleX(-1);
}
// Progress paused
// --------------------------------------------------
// Progress Bar: Paused
// ------------------------------------------------------------------------
:host(.progress-paused) {
.indeterminate-bar-secondary,
@ -158,8 +155,27 @@
}
}
// Animation Keyframes
// --------------------------------------------------
// Progress Bar: Color
// ------------------------------------------------------------------------
:host(.ion-color) .progress-buffer-bar {
background: #{current-color(base, 0.3)};
}
:host(.ion-color) .buffer-circles {
background-image: radial-gradient(ellipse at center, #{current-color(base, 0.3)} 0%, #{current-color(base, 0.3)} 30%, transparent 30%);
}
:host(.ion-color) {
.progress,
.progress-indeterminate {
background: #{current-color(base)};
}
}
// Progress Bar: Animation Keyframes
// ------------------------------------------------------------------------
// Source: https://github.com/material-components/material-components-web/blob/master/packages/mdc-linear-progress/_keyframes.scss
@keyframes primary-indeterminate-translate {
@ -259,3 +275,4 @@
transform: translateX(-10px);
}
}

View File

@ -8,6 +8,11 @@ import { createColorClasses } from '../../utils/theme';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part progress - The progress bar that shows the current value when `type` is `"determinate"` and slides back and forth when `type` is `"indeterminate"`.
* @part stream - The animated circles that appear while buffering. This only shows when `buffer` is set and `type` is `"determinate"`.
* @part track - The track bar behind the progress bar. If the `buffer` property is set and `type` is `"determinate"` the track will be the
* width of the `buffer` value.
*/
@Component({
tag: 'ion-progress-bar',
@ -77,10 +82,12 @@ export class ProgressBar implements ComponentInterface {
}
const renderIndeterminate = () => {
return [
<div class="indeterminate-bar-primary"><span class="progress-indeterminate"></span></div>,
<div class="indeterminate-bar-secondary"><span class="progress-indeterminate"></span></div>
];
return (
<div part="track" class="progress-buffer-bar">
<div class="indeterminate-bar-primary"><span part="progress" class="progress-indeterminate"></span></div>
<div class="indeterminate-bar-secondary"><span part="progress" class="progress-indeterminate"></span></div>
</div>
);
};
const renderProgress = (value: number, buffer: number) => {
@ -88,7 +95,7 @@ const renderProgress = (value: number, buffer: number) => {
const finalBuffer = clamp(0, buffer, 1);
return [
<div class="progress" style={{ transform: `scaleX(${finalValue})` }}></div>,
<div part="progress" class="progress" style={{ transform: `scaleX(${finalValue})` }}></div>,
/**
* Buffer circles with two container to move
* the circles behind the buffer progress
@ -98,9 +105,9 @@ const renderProgress = (value: number, buffer: number) => {
*/
<div class={{ 'buffer-circles-container': true, 'ion-hide': finalBuffer === 1 }} style={{ transform: `translateX(${finalBuffer * 100}%)` }}>
<div class="buffer-circles-container" style={{ transform: `translateX(-${finalBuffer * 100}%)` }}>
<div class="buffer-circles"></div>
<div part="stream" class="buffer-circles"></div>
</div>
</div>,
<div class="progress-buffer-bar" style={{ transform: `scaleX(${finalBuffer})` }}></div>,
<div part="track" class="progress-buffer-bar" style={{ transform: `scaleX(${finalBuffer})` }}></div>,
];
};

View File

@ -1,20 +1,18 @@
# ion-progress-bar
ion-progress-bar is a horizontal progress bar to visualize the progression of an operation and activity. You can choose between two types: `determinate` and `indeterminate`.
Progress bars inform users about the status of ongoing processes, such as loading an app, submitting a form, or saving updates. There are two types of progress bars: `determinate` and `indeterminate`.
## Progress Type
### Determinate
If the percentage of an operation is known, you should use the determinate type. This is the default type and the progress is represented by the `value` property.
Determinate is the default type. It should be used when the percentage of an operation is known. The progress is represented by setting the `value` property. This can be used to show the progress increasing from 0 to 100% of the track.
A buffer shows circles as animation to indicate some activity. If the `buffer` property is smaller than 1 you can show the additional buffering progress.
If the `buffer` property is set, a buffer stream will show with animated circles to indicate activity. The value of the `buffer` property will also be represented by how much visible track there is. If the value of `buffer` is less than the `value` property, there will be no visible track. If `buffer` is equal to `1` then the buffer stream will be hidden.
### Indeterminate
If an operation is in progress and it's not necessary to indicate how long it will take.
If you add `reversed="true"`, you receive a query which is used to indicate pre-loading.
The indeterminate type should be used when it is unknown how long the process will take. The progress bar is not tied to the `value`, instead it continually slides along the track until the process is complete.
<!-- Auto Generated Below -->
@ -144,13 +142,22 @@ export default defineComponent({
| `value` | `value` | The value determines how much of the active bar should display when the `type` is `"determinate"`. The value should be between [0, 1]. | `number` | `0` |
## Shadow Parts
| Part | Description |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"progress"` | The progress bar that shows the current value when `type` is `"determinate"` and slides back and forth when `type` is `"indeterminate"`. |
| `"stream"` | The animated circles that appear while buffering. This only shows when `buffer` is set and `type` is `"determinate"`. |
| `"track"` | The track bar behind the progress bar. If the `buffer` property is set and `type` is `"determinate"` the track will be the width of the `buffer` value. |
## CSS Custom Properties
| Name | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `--background` | Same as --buffer-background when using a determinate progress bar, otherwise it styles the background of the ion-progress-bar itself. |
| `--buffer-background` | Color of the buffer bar |
| `--progress-background` | Color of the progress bar |
| Name | Description |
| ----------------------- | ---------------------------------------------------------------------- |
| `--background` | Background of the progress track, or the buffer bar if `buffer` is set |
| `--buffer-background` | DEPRECATED, use `--background` instead |
| `--progress-background` | Background of the progress bar representing the current value |
----------------------------------------------

View File

@ -0,0 +1,10 @@
import { newE2EPage } from '@stencil/core/testing';
test('progress-bar: standalone', async () => {
const page = await newE2EPage({
url: '/src/components/progress-bar/test/standalone?ionic:_testing=true'
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});

View File

@ -12,19 +12,171 @@
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script></head>
<body>
<h1>Default Progress Bar</h1>
<h1>Default Progress Bars</h1>
<ion-progress-bar></ion-progress-bar>
<h1>Default Progress Bar with 50% width</h1>
<ion-progress-bar value="0.5"></ion-progress-bar>
<ion-progress-bar type="indeterminate"></ion-progress-bar>
<hr>
<h1>Colorize Progress Bar</h1>
<h1>Progress Bar: Colors</h1>
<ion-progress-bar color="primary" value="0.5"></ion-progress-bar>
<ion-progress-bar color="secondary" value="0.5"></ion-progress-bar>
<ion-progress-bar color="tertiary" value="0.5"></ion-progress-bar>
<ion-progress-bar color="success" value="0.5"></ion-progress-bar>
<ion-progress-bar color="warning" value="0.5"></ion-progress-bar>
<ion-progress-bar color="danger" value="0.5"></ion-progress-bar>
<ion-progress-bar color="dark" value="0.5"></ion-progress-bar>
<ion-progress-bar color="light" value="0.5"></ion-progress-bar>
<h1>Other types</h1>
<ion-progress-bar type="indeterminate"></ion-progress-bar>
<hr>
<h1>Default Types</h1>
<ion-progress-bar></ion-progress-bar>
<ion-progress-bar value="0.5"></ion-progress-bar>
<ion-progress-bar value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar color="warning" reversed="true" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar buffer="0"></ion-progress-bar>
<ion-progress-bar color="danger" type="indeterminate"></ion-progress-bar>
<ion-progress-bar type="indeterminate" reversed="true"></ion-progress-bar>
<hr>
<h1>Custom: colors by part</h1>
<ion-progress-bar class="custom-color-parts"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" buffer="0.9"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" value="0.5"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" color="warning" reversed="true" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" buffer="0"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" color="danger" type="indeterminate"></ion-progress-bar>
<ion-progress-bar class="custom-color-parts" type="indeterminate" reversed="true"></ion-progress-bar>
<hr>
<h1>Custom: colors by css variable</h1>
<ion-progress-bar class="custom-color-variables"></ion-progress-bar>
<ion-progress-bar class="custom-color-variables" value="0.5"></ion-progress-bar>
<ion-progress-bar class="custom-color-variables" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar class="custom-color-variables" color="warning" reversed="true" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar class="custom-color-variables" buffer="0"></ion-progress-bar>
<ion-progress-bar class="custom-color-variables" color="danger" type="indeterminate"></ion-progress-bar>
<ion-progress-bar class="custom-color-variables" type="indeterminate" reversed="true"></ion-progress-bar>
<hr>
<h1>Custom border radius</h1>
<ion-progress-bar class="custom-border-radius"></ion-progress-bar>
<ion-progress-bar class="custom-border-radius" value="0.5"></ion-progress-bar>
<ion-progress-bar class="custom-border-radius" type="indeterminate"></ion-progress-bar>
<h1>Custom transition</h1>
<ion-progress-bar class="random-value" max="100"></ion-progress-bar>
<ion-progress-bar class="random-value custom-transition" max="100"></ion-progress-bar>
</body>
<script>
let randomValues = document.querySelectorAll('.random-value');
setInterval(() => {
let value = Math.random();
for (let i = 0; i < randomValues.length; i++) {
randomValues[i].value = value;
}
}, 100);
</script>
<style>
h1 {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 12px;
font-weight: normal;
color: #a1a7b0;
margin-top: 10px;
margin-left: 5px;
}
hr {
background: #eff1f3;
border: none;
height: 1px;
margin-top: 18px;
margin-bottom: 25px;
}
ion-progress-bar {
margin-bottom: 10px;
}
/*
* Custom progress bar color using parts
* ------------------------------------------------------
* Note: in these examples setting the background on
* each element should override the color prop
*/
/* determinate buffer / track and indeterminate track */
.custom-color-parts::part(track) {
background:rgb(158, 157, 36, 0.2);
}
/* determinate and indeterminate progress background */
.custom-color-parts::part(progress) {
background: #9e9d24;
}
/* buffer stream (animated circles) */
.custom-color-parts::part(stream) {
background-image: radial-gradient(ellipse at center, rgb(158, 157, 36, 0.2) 0%, rgb(158, 157, 36, 0.2) 30%, transparent 30%);
}
/*
* Custom progress bar color using css variables
* ------------------------------------------------------
* Note: in this example setting the background via
* CSS variables should NOT override the color prop
*/
.custom-color-variables {
--background: rgb(158, 157, 36, 0.2);
--progress-background: #9e9d24;
}
/*
* Custom progress bar border radius using parts
* ------------------------------------------------------
*/
.custom-border-radius {
border-radius: 10px;
height: 20px;
}
.custom-border-radius::part(progress) {
border-radius: 0 50% 50% 0;
}
.custom-border-radius[type="indeterminate"]::part(progress) {
border-radius: 8px;
}
/*
* Custom transition for fast value changes
* ------------------------------------------------------
* The first progress bar in the example has the default
* transition, while the second has none. This is
* apparent because they use the same values.
*/
.custom-transition::part(progress) {
transition: none;
}
</style>
</html>