feat(accordion-group): add default styles for the ionic theme (#29938)

Adds the following:
- An ionic theme file with styles for the Accordion Group
- An e2e test for the `expand` property with screenshots of the default (compact) expand and `"inset"`
- An e2e test for states with screenshots of a disabled Accordion Group
This commit is contained in:
Brandy Carney
2024-10-16 11:56:18 -04:00
committed by GitHub
parent 85ec5f7b2c
commit f4766c6738
26 changed files with 455 additions and 21 deletions

View File

@ -0,0 +1,6 @@
// Accordion Group: Common
// --------------------------------------------------
:host {
display: block;
}

View File

@ -0,0 +1,20 @@
@use "../../themes/ionic/ionic.globals.scss" as globals;
@use "./accordion-group.common";
// Ionic Accordion Group
// --------------------------------------------------
:host {
min-width: 272px;
background-color: globals.$ionic-color-base-white;
}
// Inset Accordion Group
// --------------------------------------------------
// Shape and padding only apply if the group is inset
:host(.accordion-group-expand-inset) {
@include globals.border-radius(globals.$ionic-border-radius-400);
@include globals.padding(globals.$ionic-space-100);
}

View File

@ -1,4 +1,4 @@
@import "./accordion-group"; @import "./accordion-group.native";
// iOS Accordion Group // iOS Accordion Group
// -------------------------------------------------- // --------------------------------------------------

View File

@ -1,4 +1,4 @@
@import "./accordion-group"; @import "./accordion-group.native";
@import "../accordion/accordion.md.vars"; @import "../accordion/accordion.md.vars";
// Material Design Accordion Group // Material Design Accordion Group

View File

@ -1,13 +1,10 @@
@import "./accordion-group.common";
@import "../../themes/native/native.globals"; @import "../../themes/native/native.globals";
@import "../accordion/accordion.vars"; @import "../accordion/accordion.vars";
// Accordion Group // Accordion Group: Native
// -------------------------------------------------- // --------------------------------------------------
:host {
display: block;
}
:host(.accordion-group-expand-inset) { :host(.accordion-group-expand-inset) {
@include margin($accordion-inset-margin, $accordion-inset-margin, $accordion-inset-margin, $accordion-inset-margin); @include margin($accordion-inset-margin, $accordion-inset-margin, $accordion-inset-margin, $accordion-inset-margin);
} }

View File

@ -15,7 +15,7 @@ import type { AccordionGroupChangeEventDetail } from './accordion-group-interfac
styleUrls: { styleUrls: {
ios: 'accordion-group.ios.scss', ios: 'accordion-group.ios.scss',
md: 'accordion-group.md.scss', md: 'accordion-group.md.scss',
ionic: 'accordion-group.md.scss', ionic: 'accordion-group.ionic.scss',
}, },
shadow: true, shadow: true,
}) })

View File

@ -0,0 +1,162 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('accordion-group: expand'), () => {
test.describe(title('compact'), () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<style>
/* Background styles to show the border radius */
:root {
background: #ccc7c7;
}
</style>
<ion-accordion-group>
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
`,
config
);
const accordionGroup = page.locator('ion-accordion-group');
await expect(accordionGroup).toHaveScreenshot(screenshot('accordion-group-expand-compact'));
});
test('should not have visual regressions when expanded', async ({ page }) => {
await page.setContent(
`
<style>
/* Background styles to show the border radius */
:root {
background: #ccc7c7;
}
</style>
<ion-accordion-group value="first">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
`,
config
);
const accordionGroup = page.locator('ion-accordion-group');
await expect(accordionGroup).toHaveScreenshot(screenshot('accordion-group-expand-compact-expanded'));
});
});
test.describe(title('inset'), () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<style>
/* Background styles to show the border radius */
:root {
background: #ccc7c7;
}
</style>
<ion-accordion-group expand="inset">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
`,
config
);
const accordionGroup = page.locator('ion-accordion-group');
await expect(accordionGroup).toHaveScreenshot(screenshot('accordion-group-expand-inset'));
});
test('should not have visual regressions when expanded', async ({ page }) => {
await page.setContent(
`
<style>
/* Background styles to show the border radius */
:root {
background: #ccc7c7;
}
</style>
<ion-accordion-group value="first" expand="inset">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
`,
config
);
const accordionGroup = page.locator('ion-accordion-group');
await expect(accordionGroup).toHaveScreenshot(screenshot('accordion-group-expand-inset-expanded'));
});
});
});
});

View File

@ -0,0 +1,135 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Accordion Group - Expand</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-row-gap: 20px;
grid-column-gap: 20px;
}
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
margin-left: 5px;
}
</style>
</head>
<body>
<ion-app>
<ion-header translucent="true">
<ion-toolbar>
<ion-title>Accordion Group - Expand</ion-title>
</ion-toolbar>
</ion-header>
<ion-content fullscreen="true" color="light">
<div class="grid ion-padding">
<div class="grid-item">
<h2>Default</h2>
<ion-accordion-group>
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Default: Expanded</h2>
<ion-accordion-group value="first">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Inset</h2>
<ion-accordion-group expand="inset">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Inset: Expanded</h2>
<ion-accordion-group value="first" expand="inset">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
</div>
</div>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -0,0 +1,38 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('accordion-group: states'), () => {
test('should render disabled state', async ({ page }) => {
await page.setContent(
`
<ion-accordion-group value="first" disabled="true">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
`,
config
);
const accordionGroup = page.locator('ion-accordion-group');
await expect(accordionGroup).toHaveScreenshot(screenshot('accordion-group-disabled'));
});
});
});

View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Accordion Group - States</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-row-gap: 20px;
grid-column-gap: 20px;
}
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
margin-left: 5px;
}
</style>
</head>
<body>
<ion-app>
<ion-header translucent="true">
<ion-toolbar>
<ion-title>Accordion Group - States</ion-title>
</ion-toolbar>
</ion-header>
<ion-content fullscreen="true" color="light">
<div class="grid ion-padding">
<div class="grid-item">
<h2>Default</h2>
<ion-accordion-group value="first">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
</div>
<div class="grid-item">
<h2>Disabled</h2>
<ion-accordion-group value="first" disabled="true">
<ion-accordion value="first">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="second">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
<ion-accordion value="third">
<ion-item slot="header">
<ion-label>Accordion title</ion-label>
</ion-item>
<div slot="content">This is the body of the accordion.</div>
</ion-accordion>
</ion-accordion-group>
</div>
</div>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -309,9 +309,6 @@ ion-accordion-group.accordion-group-expand-inset > ion-accordion:last-of-type {
border-bottom-left-radius: globals.$ionic-border-radius-200; border-bottom-left-radius: globals.$ionic-border-radius-200;
border-bottom-right-radius: globals.$ionic-border-radius-200; border-bottom-right-radius: globals.$ionic-border-radius-200;
} }
ion-accordion-group > ion-accordion:last-of-type ion-item[slot="header"] {
--border-width: 0;
}
ion-accordion.accordion-animated > [slot="header"] .ion-accordion-toggle-icon { ion-accordion.accordion-animated > [slot="header"] .ion-accordion-toggle-icon {
transition: 300ms transform cubic-bezier(0.25, 0.8, 0.5, 1); transition: 300ms transform cubic-bezier(0.25, 0.8, 0.5, 1);
@ -334,16 +331,6 @@ ion-accordion.accordion-expanded > [slot="header"] .ion-accordion-toggle-icon {
transform: rotate(180deg); transform: rotate(180deg);
} }
ion-accordion-group.accordion-group-expand-inset.md > ion-accordion.accordion-previous ion-item[slot="header"] {
--border-width: 0;
--inner-border-width: 0;
}
ion-accordion-group.accordion-group-expand-inset.md > ion-accordion.accordion-expanding:first-of-type,
ion-accordion-group.accordion-group-expand-inset.md > ion-accordion.accordion-expanded:first-of-type {
margin-top: 0;
}
// Safari/iOS 15 changes the appearance of input[type="date"]. // Safari/iOS 15 changes the appearance of input[type="date"].
// For backwards compatibility from Ionic 5/Safari 14 designs, // For backwards compatibility from Ionic 5/Safari 14 designs,
// we override the appearance only when using within an ion-input. // we override the appearance only when using within an ion-input.