Merge remote-tracking branch 'origin/main' into sync-feat-74
@@ -46,7 +46,8 @@ module.exports = {
|
||||
{
|
||||
"files": ["*.e2e.ts"],
|
||||
"rules": {
|
||||
"custom-rules/await-playwright-promise-assertion": "error"
|
||||
"custom-rules/await-playwright-promise-assertion": "error",
|
||||
"custom-rules/no-playwright-to-match-snapshot-assertion": "error"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.3.3](https://github.com/ionic-team/ionic-framework/compare/v7.3.2...v7.3.3) (2023-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **modal:** swipe to dismiss resets status bar style ([#28110](https://github.com/ionic-team/ionic-framework/issues/28110)) ([176585f](https://github.com/ionic-team/ionic-framework/commit/176585f446b04a6a0cedab2e09417637dbfc78ee)), closes [#28105](https://github.com/ionic-team/ionic-framework/issues/28105)
|
||||
* **overlays:** prevent overlays from getting stuck open ([#28069](https://github.com/ionic-team/ionic-framework/issues/28069)) ([584e9d3](https://github.com/ionic-team/ionic-framework/commit/584e9d3be220343451c2d4b9bf90658ecd530de1)), closes [#27200](https://github.com/ionic-team/ionic-framework/issues/27200)
|
||||
* **popover:** dynamic width popover is positioned correctly ([#28072](https://github.com/ionic-team/ionic-framework/issues/28072)) ([2a80eb6](https://github.com/ionic-team/ionic-framework/commit/2a80eb6bd0b16a9dab9bea600bb7f935d25c0e1b)), closes [#27190](https://github.com/ionic-team/ionic-framework/issues/27190) [#24780](https://github.com/ionic-team/ionic-framework/issues/24780)
|
||||
* **textarea:** cols property is respected ([#28081](https://github.com/ionic-team/ionic-framework/issues/28081)) ([6d4eabc](https://github.com/ionic-team/ionic-framework/commit/6d4eabcc1046c28c1abf69a8bda3e06f80cf3f8f)), closes [#22142](https://github.com/ionic-team/ionic-framework/issues/22142)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.3.2](https://github.com/ionic-team/ionic-framework/compare/v7.3.1...v7.3.2) (2023-08-30)
|
||||
|
||||
|
||||
|
||||
@@ -1370,7 +1370,7 @@ ion-textarea,prop,autocapitalize,string,'none',false,false
|
||||
ion-textarea,prop,autofocus,boolean,false,false,false
|
||||
ion-textarea,prop,clearOnEdit,boolean,false,false,false
|
||||
ion-textarea,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||
ion-textarea,prop,cols,number | undefined,undefined,false,false
|
||||
ion-textarea,prop,cols,number | undefined,undefined,false,true
|
||||
ion-textarea,prop,counter,boolean,false,false,false
|
||||
ion-textarea,prop,counterFormatter,((inputLength: number, maxLength: number) => string) | undefined,undefined,false,false
|
||||
ion-textarea,prop,debounce,number | undefined,undefined,false,false
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-component-on-ready-method': require('./no-component-on-ready-method.js'),
|
||||
'await-playwright-promise-assertion': require('./await-playwright-promise-assertion.js')
|
||||
'await-playwright-promise-assertion': require('./await-playwright-promise-assertion.js'),
|
||||
'no-playwright-to-match-snapshot-assertion': require('./no-playwright-to-match-snapshot-assertion.js')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
module.exports = {
|
||||
meta: {
|
||||
messages: {
|
||||
noPlaywrightToMatchSnapshotAssertion: '"toHaveScreenshot" assertions should be used in favor of "toMatchSnapshot". "toHaveScreenshot" brings file size reductions and anti-flake behaviors such as disabling animations by default.',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ExpressionStatement(node) {
|
||||
if (node.expression.callee === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { property } = node.expression.callee;
|
||||
|
||||
/**
|
||||
* Check to see if toMatchSnapshot is being used
|
||||
*/
|
||||
if (
|
||||
property !== undefined &&
|
||||
property.type === 'Identifier' &&
|
||||
property.name === 'toMatchSnapshot'
|
||||
) {
|
||||
context.report({ node: node, messageId: 'noPlaywrightToMatchSnapshotAssertion' });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
18
core/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.3.2",
|
||||
"version": "7.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "7.3.2",
|
||||
"version": "7.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.1.0",
|
||||
"@stencil/core": "^4.2.0",
|
||||
"ionicons": "7.1.0",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
@@ -1634,9 +1634,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-yIpL+CX02fy5zvFXwXcHZjjEILRm3aiONbucpfLIWPS7zcBAuucdROssartEa+D7E1JRko97ydxn1Ntdu4GoWg==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.2.0.tgz",
|
||||
"integrity": "sha512-HhxRs/b/VHTCM35lunFCzYajRQeYezsJQGgalENNpkrKUOPMvzv0dalXe8Yn/8p9eyn+GZVZuWLd0CAR4VWBbA==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
@@ -11524,9 +11524,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-yIpL+CX02fy5zvFXwXcHZjjEILRm3aiONbucpfLIWPS7zcBAuucdROssartEa+D7E1JRko97ydxn1Ntdu4GoWg=="
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.2.0.tgz",
|
||||
"integrity": "sha512-HhxRs/b/VHTCM35lunFCzYajRQeYezsJQGgalENNpkrKUOPMvzv0dalXe8Yn/8p9eyn+GZVZuWLd0CAR4VWBbA=="
|
||||
},
|
||||
"@stencil/react-output-target": {
|
||||
"version": "0.5.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.3.2",
|
||||
"version": "7.3.3",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -31,7 +31,7 @@
|
||||
"loader/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.1.0",
|
||||
"@stencil/core": "^4.2.0",
|
||||
"ionicons": "7.1.0",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
|
||||
@@ -55,9 +55,6 @@ const config: PlaywrightTestConfig = {
|
||||
timeout: 5000,
|
||||
toHaveScreenshot: {
|
||||
threshold: 0.1
|
||||
},
|
||||
toMatchSnapshot: {
|
||||
threshold: 0.1
|
||||
}
|
||||
},
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 25 KiB |
82
core/src/components/progress-bar/test/buffer/index.html
Normal 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>
|
||||
@@ -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`));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 172 B |
|
After Width: | Height: | Size: 173 B |
|
After Width: | Height: | Size: 139 B |
91
core/src/components/progress-bar/test/determinate/index.html
Normal 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>
|
||||
@@ -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`));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 145 B |
|
After Width: | Height: | Size: 127 B |
@@ -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(
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
43
core/src/components/textarea/test/cols/textarea.e2e.ts
Normal 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'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||