feat(accordion): add shape styles for the ionic theme (#29973)

- Applies border radius based on the `shape` defined on the parent accordion group
- Adds an e2e test for shape with focused items to show the border radius
- Adds screenshots for the e2e test
This commit is contained in:
Brandy Carney
2024-10-31 11:35:35 -04:00
committed by GitHub
parent 4f61e0170d
commit d4ff124737
17 changed files with 216 additions and 19 deletions

View File

@ -19,13 +19,19 @@
}
:host(.accordion-group-expand-inset.accordion-group-shape-round) {
--border-radius: #{globals.$ion-border-radius-400};
@include globals.border-radius(globals.$ion-border-radius-400);
}
:host(.accordion-group-expand-inset.accordion-group-shape-soft) {
--border-radius: #{globals.$ion-border-radius-200};
@include globals.border-radius(globals.$ion-border-radius-200);
}
:host(.accordion-group-expand-inset.accordion-group-shape-rectangular) {
--border-radius: #{globals.$ion-border-radius-0};
@include globals.border-radius(globals.$ion-border-radius-0);
}

View File

@ -1,6 +1,3 @@
// @import "../../themes/functions.string";
// @import "../../themes/mixins";
// Accordion: Common
// --------------------------------------------------

View File

@ -42,7 +42,7 @@
// The border is removed from the item in the header because
// we are adding a border to the ::after element of the accordion.
::slotted(ion-item[slot="header"]) {
--border-radius: #{globals.$ion-border-radius-0};
--border-radius: inherit;
--color: #{globals.$ion-primitives-neutral-1200};
--border-width: 0;
--inner-border-width: 0;
@ -55,11 +55,6 @@
@include globals.typography(globals.$ion-heading-h6-medium);
}
// Shape only applies when inside an inset accordion group
:host(.in-accordion-group-expand-inset) ::slotted(ion-item[slot="header"]) {
--border-radius: #{globals.$ion-border-radius-400};
}
// Accordion Content
// --------------------------------------------------

View File

@ -0,0 +1,48 @@
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: shape'), () => {
['round', 'soft', 'rectangular'].forEach((shape) => {
test(`${shape} - should not have visual regressions`, async ({ page }) => {
await page.setContent(
`
<style>
/* Background styles to show the border radius */
:root {
background: #222;
}
</style>
<!-- Focused accordion to show the border radius -->
<ion-accordion-group value="first" expand="inset" shape="${shape}">
<ion-accordion value="first">
<ion-item slot="header" class="ion-focused">
<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-shape-${shape}`));
});
});
});
});

View File

@ -0,0 +1,135 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Accordion - Shape</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(4, 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 - Shape</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 expand="inset" value="first">
<ion-accordion value="first">
<ion-item slot="header" class="ion-focused">
<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>Round</h2>
<ion-accordion-group expand="inset" value="first" shape="round">
<ion-accordion value="first">
<ion-item slot="header" class="ion-focused">
<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>Soft</h2>
<ion-accordion-group expand="inset" value="first" shape="soft">
<ion-accordion value="first">
<ion-item slot="header" class="ion-focused">
<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>Rectangular</h2>
<ion-accordion-group expand="inset" value="first" shape="rectangular">
<ion-accordion value="first">
<ion-item slot="header" class="ion-focused">
<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

@ -47,6 +47,7 @@ body.backdrop-no-scroll {
// Modal - Card Style
// --------------------------------------------------
/**
* Card style modal needs additional padding on the
* top of the header. We accomplish this by targeting
@ -293,14 +294,18 @@ ion-card-header.ion-color .ion-inherit-color {
}
// Accordion Styles
// --------------------------------------------------
ion-accordion-group.accordion-group-expand-inset > ion-accordion:first-of-type {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
ion-accordion-group.accordion-group-expand-inset > ion-accordion:last-of-type {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
ion-accordion-group > ion-accordion:last-of-type ion-item[slot="header"] {
--border-width: 0px;
}
@ -315,6 +320,7 @@ ion-accordion.accordion-animated > [slot="header"] .ion-accordion-toggle-icon {
transition: none !important;
}
}
/**
* The > [slot="header"] selector ensures that we do
* not modify toggle icons for any nested accordions. The state
@ -336,6 +342,9 @@ ion-accordion-group.accordion-group-expand-inset.md > ion-accordion.accordion-ex
margin-top: 0;
}
// Datetime Styles
// --------------------------------------------------
// Safari/iOS 15 changes the appearance of input[type="date"].
// For backwards compatibility from Ionic 5/Safari 14 designs,
// we override the appearance only when using within an ion-input.
@ -383,6 +392,9 @@ h1[tabindex="-1"]:focus,
outline: none;
}
// Popover Styles
// --------------------------------------------------
/*
* If a popover has a child ion-content (or class equivalent) then the .popover-viewport element
* should not be scrollable to ensure the inner content does scroll. However, if the popover

View File

@ -36,6 +36,7 @@ body.backdrop-no-scroll {
// Modal - Card Style
// --------------------------------------------------
html.ionic ion-modal ion-header {
box-shadow: none;
}
@ -301,14 +302,7 @@ ion-card-header.ion-color .ion-inherit-color {
}
// Accordion Styles
ion-accordion-group.accordion-group-expand-inset > ion-accordion:first-of-type {
border-top-left-radius: globals.$ion-border-radius-200;
border-top-right-radius: globals.$ion-border-radius-200;
}
ion-accordion-group.accordion-group-expand-inset > ion-accordion:last-of-type {
border-bottom-left-radius: globals.$ion-border-radius-200;
border-bottom-right-radius: globals.$ion-border-radius-200;
}
// --------------------------------------------------
// The toggle icon is nested in the accordion item so we need to
// style it from a global level.
@ -327,6 +321,7 @@ ion-accordion.accordion-animated > [slot="header"] .ion-accordion-toggle-icon {
transition: none !important;
}
}
/**
* The > [slot="header"] selector ensures that we do
* not modify toggle icons for any nested accordions. The state
@ -352,6 +347,9 @@ ion-accordion > [slot="content"] ion-item {
--min-height: #{globals.$ion-scale-700};
}
// Datetime Styles
// --------------------------------------------------
// Safari/iOS 15 changes the appearance of input[type="date"].
// For backwards compatibility from Ionic 5/Safari 14 designs,
// we override the appearance only when using within an ion-input.
@ -382,6 +380,9 @@ ion-input input::-webkit-date-and-time-value {
min-height: 320px;
}
// Popover Styles
// --------------------------------------------------
/**
* If a popover has a child ion-content (or class equivalent) then the .popover-viewport element
* should not be scrollable to ensure the inner content does scroll. However, if the popover

View File

@ -43,8 +43,11 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
<title>Ionic Playwright Test</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="${baseUrl}/css/ionic.bundle.css" rel="stylesheet" />
${theme === 'ionic' ? `<link href="${baseUrl}/css/ionic/bundle.ionic.css" rel="stylesheet" />` : ''}
${
theme === 'ionic'
? `<link href="${baseUrl}/css/ionic/bundle.ionic.css" rel="stylesheet" />`
: `<link href="${baseUrl}/css/ionic.bundle.css" rel="stylesheet" />`
}
<link href="${baseUrl}/scripts/testing/styles.css" rel="stylesheet" />
${palette !== 'light' ? `<link href="${baseUrl}/css/palettes/${palette}.always.css" rel="stylesheet" />` : ''}
<script src="${baseUrl}/scripts/testing/scripts.js"></script>