Merge remote-tracking branch 'origin/main' into sync-feat-74

This commit is contained in:
Liam DeBeasi
2023-09-11 09:23:16 -04:00
100 changed files with 709 additions and 195 deletions

View File

@ -59,15 +59,73 @@
}
:host(.menu-side-start) .menu-inner {
/**
* Menu does not cover the whole screen so we need to set the safe area for the
* side that touches the screen edge only. Since safe area is not logical, it
* needs to be applied to the correct side depending on the language direction.
* Otherwise, the content will have less space on both sides.
*
* LTR:
* The left side of the menu touches the screen edge. The safe area padding has
* already been set in the core styles, so there's no need to set it again.
* The right side of the menu is not touching the screen edge. Padding is not
* applied to the right side of the menu. A value of 0 is set.
*/
--ion-safe-area-right: 0px;
@include position(0, auto, 0, 0);
@include rtl() {
/**
* Menu does not cover the whole screen so we need to set the safe area for the
* side that touches the screen edge only. Since safe area is not logical, it
* needs to be applied to the correct side depending on the language direction.
* Otherwise, the content will have less space on both sides.
*
* RTL:
* The right side of the menu touches the screen edge. The safe area padding has
* already been set in the core styles, so there's no need to set it again.
* The left side of the menu is not touching the screen edge. Padding is not
* applied to the left side of the menu. A value of 0 is set.
*/
--ion-safe-area-right: env(safe-area-inset-right);
--ion-safe-area-left: 0px;
}
}
:host(.menu-side-end) .menu-inner {
/**
* Menu does not cover the whole screen so we need to set the safe area for the
* side that touches the screen edge only. Since safe area is not logical, it
* needs to be applied to the correct side depending on the language direction.
* Otherwise, the content will have less space on both sides.
*
* LTR:
* The right side of the menu touches the screen edge. The safe area padding has
* already been set in the core styles, so there's no need to set it again.
* The left side of the menu is not touching the screen edge. Padding is not
* applied to the left side of the menu. A value of 0 is set.
*/
--ion-safe-area-left: 0px;
@include position(0, 0, 0, auto);
@include rtl() {
/**
* Menu does not cover the whole screen so we need to set the safe area for the
* side that touches the screen edge only. Since safe area is not logical, it
* needs to be applied to the correct side depending on the language direction.
* Otherwise, the content will have less space on both sides.
*
* RTL:
* The left side of the menu touches the screen edge. The safe area padding has
* already been set in the core styles, so there's no need to set it again.
* The right side of the menu is not touching the screen edge. Padding is not
* applied to the right side of the menu. A value of 0 is set.
*/
--ion-safe-area-left: env(safe-area-inset-left);
--ion-safe-area-right: 0px;
}
}
ion-backdrop {

View File

@ -473,6 +473,19 @@ export class Modal implements ComponentInterface, OverlayInterface {
writeTask(() => this.el.classList.add('show-modal'));
const hasCardModal = presentingElement !== undefined;
/**
* We need to change the status bar at the
* start of the animation so that it completes
* by the time the card animation is done.
*/
if (hasCardModal && getIonMode(this) === 'ios') {
// Cache the original status bar color before the modal is presented
this.statusBarStyle = await StatusBar.getStyle();
setCardStatusBarDark();
}
await present<ModalPresentOptions>(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
presentingEl: presentingElement,
currentBreakpoint: this.initialBreakpoint,
@ -511,19 +524,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
window.addEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
}
const hasCardModal = presentingElement !== undefined;
/**
* We need to change the status bar at the
* start of the animation so that it completes
* by the time the card animation is done.
*/
if (hasCardModal && getIonMode(this) === 'ios') {
// Cache the original status bar color before the modal is presented
this.statusBarStyle = await StatusBar.getStyle();
setCardStatusBarDark();
}
if (this.isSheetModal) {
this.initSheetGesture();
} else if (hasCardModal) {
@ -566,6 +566,16 @@ export class Modal implements ComponentInterface, OverlayInterface {
* removed from the DOM.
*/
this.gestureAnimationDismissing = true;
/**
* Reset the status bar style as the dismiss animation
* starts otherwise the status bar will be the wrong
* color for the duration of the dismiss animation.
* The dismiss method does this as well, but
* in this case it's only called once the animation
* has finished.
*/
setCardStatusBarDefault(this.statusBarStyle);
this.animation!.onFinish(async () => {
await this.dismiss(undefined, GESTURE);
this.gestureAnimationDismissing = false;

View File

@ -79,18 +79,6 @@
</ion-list-header>
<ion-progress-bar class="custom-bar-background" value="0.75"></ion-progress-bar>
<ion-list-header>
<ion-label> Determinate (change progress with slider) </ion-label>
</ion-list-header>
<ion-progress-bar id="progressBar"></ion-progress-bar>
<ion-item>
<ion-range legacy="true" pin="true" value="0" id="progressValue">
<ion-label slot="start">0</ion-label>
<ion-label slot="end">100</ion-label>
</ion-range>
</ion-item>
<ion-list-header>
<ion-label> Buffer </ion-label>
</ion-list-header>
@ -105,39 +93,8 @@
<ion-label> Buffer (without value) </ion-label>
</ion-list-header>
<ion-progress-bar color="tertiary" buffer="0"></ion-progress-bar>
<ion-list-header>
<ion-label> Buffer (change buffer with slider) </ion-label>
</ion-list-header>
<ion-progress-bar class="progressBarBuffer" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar class="progressBarBuffer" value="0.20" buffer="0.4" reversed="true"></ion-progress-bar>
<ion-item>
<ion-range legacy="true" pin="true" value="0" id="progressValueBuffer">
<ion-label slot="start">0</ion-label>
<ion-label slot="end">100</ion-label>
</ion-range>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
<script>
// Progress Bar Value
const progressValue = document.getElementById('progressValue');
const progressBar = document.getElementById('progressBar');
progressValue.addEventListener('ionChange', function (ev) {
progressBar.value = ev.detail.value / 100;
});
// Progress Bar Buffer
const progressValueBuffer = document.getElementById('progressValueBuffer');
const progressBarBuffer = document.querySelectorAll('.progressBarBuffer');
progressValueBuffer.addEventListener('ionChange', function (ev) {
progressBarBuffer.forEach((ele) => (ele.buffer = ev.detail.value / 100));
});
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Progress Bar - Buffer</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>
<style>
.custom-bar-background {
--buffer-background: red;
}
.no-bar-background {
--buffer-background: none;
}
ion-content ion-progress-bar {
margin: 10px 0;
}
</style>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Progress Bar - Buffer</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="outer-content">
<ion-list>
<ion-list-header>
<ion-label> Buffer </ion-label>
</ion-list-header>
<ion-progress-bar value="0.20" buffer="0.4"></ion-progress-bar>
<ion-list-header>
<ion-label> Buffer (reversed) </ion-label>
</ion-list-header>
<ion-progress-bar color="secondary" reversed="true" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-list-header>
<ion-label> Buffer (without value) </ion-label>
</ion-list-header>
<ion-progress-bar color="tertiary" buffer="0"></ion-progress-bar>
<ion-list-header>
<ion-label> Buffer (change buffer with slider) </ion-label>
</ion-list-header>
<ion-progress-bar class="progressBarBuffer" value="0.20" buffer="0.4"></ion-progress-bar>
<ion-progress-bar class="progressBarBuffer" value="0.20" buffer="0.4" reversed="true"></ion-progress-bar>
<ion-item>
<ion-range legacy="true" pin="true" value="0" id="progressValueBuffer">
<ion-label slot="start">0</ion-label>
<ion-label slot="end">100</ion-label>
</ion-range>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
<script>
// Progress Bar Buffer
const progressValueBuffer = document.getElementById('progressValueBuffer');
const progressBarBuffer = document.querySelectorAll('.progressBarBuffer');
progressValueBuffer.addEventListener('ionChange', function (ev) {
progressBarBuffer.forEach((ele) => (ele.buffer = ev.detail.value / 100));
});
</script>
</body>
</html>

View File

@ -0,0 +1,25 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('progress-bar: buffer'), () => {
test.describe('with a dynamic progress value', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-progress-bar value="0.20" buffer="0.4"></ion-progress-bar>
`,
config
);
await page.setIonViewport();
const progressBar = await page.locator('ion-progress-bar');
await progressBar.evaluate((node: HTMLIonProgressBarElement) => (node.value = 0.8));
await expect(progressBar).toHaveScreenshot(screenshot(`progress-bar-buffer-dynamic-value`));
});
});
});
});

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Progress Bar - Determinate</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>
<style>
.custom-bar-background {
--buffer-background: red;
}
.no-bar-background {
--buffer-background: none;
}
ion-content ion-progress-bar {
margin: 10px 0;
}
</style>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Progress Bar - Determinate</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="outer-content">
<ion-list>
<ion-list-header>
<ion-label> Determinate </ion-label>
</ion-list-header>
<ion-progress-bar value="0.50"></ion-progress-bar>
<ion-list-header>
<ion-label> Determinate (reversed) </ion-label>
</ion-list-header>
<ion-progress-bar reversed="true" value="0.50"></ion-progress-bar>
<ion-list-header>
<ion-label> Determinate (secondary color) </ion-label>
</ion-list-header>
<ion-progress-bar color="secondary" value="0.50"></ion-progress-bar>
<ion-list-header>
<ion-label> Determinate (with no bar background) </ion-label>
</ion-list-header>
<ion-progress-bar class="no-bar-background" value="0.75"></ion-progress-bar>
<ion-list-header>
<ion-label> Determinate (with a custom background) </ion-label>
</ion-list-header>
<ion-progress-bar class="custom-bar-background" value="0.75"></ion-progress-bar>
<ion-list-header>
<ion-label> Determinate (change progress with slider) </ion-label>
</ion-list-header>
<ion-progress-bar id="progressBar"></ion-progress-bar>
<ion-item>
<ion-range legacy="true" pin="true" value="0" id="progressValue">
<ion-label slot="start">0</ion-label>
<ion-label slot="end">100</ion-label>
</ion-range>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
<script>
// Progress Bar Value
const progressValue = document.getElementById('progressValue');
const progressBar = document.getElementById('progressBar');
progressValue.addEventListener('ionChange', function (ev) {
progressBar.value = ev.detail.value / 100;
});
</script>
</body>
</html>

View File

@ -0,0 +1,25 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('progress-bar: determinate'), () => {
test.describe('with a dynamic progress value', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-progress-bar value="0.20"></ion-progress-bar>
`,
config
);
await page.setIonViewport();
const progressBar = await page.locator('ion-progress-bar');
await progressBar.evaluate((node: HTMLIonProgressBarElement) => (node.value = 0.8));
await expect(progressBar).toHaveScreenshot(screenshot(`progress-bar-buffer-dynamic-value`));
});
});
});
});

View File

@ -17,7 +17,7 @@ configs().forEach(({ title, screenshot, config }) => {
config
);
const list = page.locator('ion-list');
await expect(list).toHaveScreenshot(screenshot(`toggle-list`));
await expect(list).toHaveScreenshot(screenshot(`radio-list`));
});
test('should render correctly in inset list', async ({ page }) => {
await page.setContent(

View File

@ -0,0 +1,43 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('textarea: cols'), () => {
test('should respect cols when autogrow is not set', async ({ page }) => {
await page.setContent(
`
<style>
ion-textarea {
border: 1px solid red;
}
</style>
<div id="container" style="width: 300px; margin: 20px;">
<ion-textarea label="Textarea" cols="5" value="Lorem Ipsum"></ion-textarea>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot('textarea-cols'));
});
test('should ignore cols when autogrow is set', async ({ page }) => {
await page.setContent(
`
<style>
ion-textarea {
border: 1px solid red;
}
</style>
<div id="container" style="width: 300px; margin: 20px;">
<ion-textarea label="Textarea" cols="5" auto-grow="true" value="Lorem Ipsum"></ion-textarea>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot('textarea-cols-autogrow'));
});
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -67,6 +67,22 @@
box-sizing: border-box;
}
/**
* When the cols property is set we should
* respect that width instead of defaulting
* to taking up the entire line.
* Requires both the cols and autoGrow
* properties to be reflected as attributes
* on the host.
*
* cols does not work with autoGrow because
* autoGrow would prevent line breaks from naturally
* occurring until the textarea takes up the entire line width.
*/
:host([cols]:not([auto-grow])) {
width: fit-content;
}
// TODO: FW-2876 - Remove this selector
:host(.legacy-textarea) {
flex: 1;

View File

@ -180,7 +180,7 @@ export class Textarea implements ComponentInterface {
/**
* The visible width of the text control, in average character widths. If it is specified, it must be a positive integer.
*/
@Prop() cols?: number;
@Prop({ reflect: true }) cols?: number;
/**
* The number of visible text lines for the control.

View File

@ -28,7 +28,6 @@
--opacity-scale: 1;
@include font-smoothing();
@include padding-horizontal(var(--ion-safe-area-left), var(--ion-safe-area-right));
display: block;
@ -36,6 +35,11 @@
width: 100%;
// stylelint-disable-next-line property-disallowed-list
padding-right: var(--ion-safe-area-right);
// stylelint-disable-next-line property-disallowed-list
padding-left: var(--ion-safe-area-left);
color: var(--color);
font-family: $font-family-base;