feat(accordion-group): add the shape property and styles for the ionic theme (#29971)
- Adds support for the `shape` property in accordion group. - Adds styles for the `"soft"`, `"round"` and `"rectangular"` shapes in the `ionic` theme - Defaults the shape to `"round"` for the ionic theme - Adds an e2e test for `shape` with screenshots of all shapes - Renames the `accordion.e2e.ts` files in other tests to `accordion-group.e2e.ts` which also renames the screenshot folder
@ -18,6 +18,7 @@ ion-accordion-group,prop,expand,"compact" | "inset",'compact',false,false
|
|||||||
ion-accordion-group,prop,mode,"ios" | "md",undefined,false,false
|
ion-accordion-group,prop,mode,"ios" | "md",undefined,false,false
|
||||||
ion-accordion-group,prop,multiple,boolean | undefined,undefined,false,false
|
ion-accordion-group,prop,multiple,boolean | undefined,undefined,false,false
|
||||||
ion-accordion-group,prop,readonly,boolean,false,false,false
|
ion-accordion-group,prop,readonly,boolean,false,false,false
|
||||||
|
ion-accordion-group,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,false
|
||||||
ion-accordion-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
ion-accordion-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||||
ion-accordion-group,prop,value,null | string | string[] | undefined,undefined,false,false
|
ion-accordion-group,prop,value,null | string | string[] | undefined,undefined,false,false
|
||||||
ion-accordion-group,event,ionChange,AccordionGroupChangeEventDetail<any>,true
|
ion-accordion-group,event,ionChange,AccordionGroupChangeEventDetail<any>,true
|
||||||
|
8
core/src/components.d.ts
vendored
@ -136,6 +136,10 @@ export namespace Components {
|
|||||||
* This method is used to ensure that the value of ion-accordion-group is being set in a valid way. This method should only be called in response to a user generated action.
|
* This method is used to ensure that the value of ion-accordion-group is being set in a valid way. This method should only be called in response to a user generated action.
|
||||||
*/
|
*/
|
||||||
"requestAccordionToggle": (accordionValue: string | undefined, accordionExpand: boolean) => Promise<void>;
|
"requestAccordionToggle": (accordionValue: string | undefined, accordionExpand: boolean) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Set to `"soft"` for an accordion group with slightly rounded corners, `"round"` for an accordion group with fully rounded corners, or `"rectangular"` for an accordion group without rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes. Only applies when `expand` is set to `"inset"`.
|
||||||
|
*/
|
||||||
|
"shape"?: 'soft' | 'round' | 'rectangular';
|
||||||
/**
|
/**
|
||||||
* The theme determines the visual appearance of the component.
|
* The theme determines the visual appearance of the component.
|
||||||
*/
|
*/
|
||||||
@ -5392,6 +5396,10 @@ declare namespace LocalJSX {
|
|||||||
* If `true`, the accordion group cannot be interacted with, but does not alter the opacity.
|
* If `true`, the accordion group cannot be interacted with, but does not alter the opacity.
|
||||||
*/
|
*/
|
||||||
"readonly"?: boolean;
|
"readonly"?: boolean;
|
||||||
|
/**
|
||||||
|
* Set to `"soft"` for an accordion group with slightly rounded corners, `"round"` for an accordion group with fully rounded corners, or `"rectangular"` for an accordion group without rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes. Only applies when `expand` is set to `"inset"`.
|
||||||
|
*/
|
||||||
|
"shape"?: 'soft' | 'round' | 'rectangular';
|
||||||
/**
|
/**
|
||||||
* The theme determines the visual appearance of the component.
|
* The theme determines the visual appearance of the component.
|
||||||
*/
|
*/
|
||||||
|
@ -12,9 +12,20 @@
|
|||||||
|
|
||||||
// Inset Accordion Group
|
// Inset Accordion Group
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
// Shape and padding only apply if the group is inset
|
// Shape and padding only apply if the group is inset
|
||||||
|
|
||||||
:host(.accordion-group-expand-inset) {
|
:host(.accordion-group-expand-inset) {
|
||||||
@include globals.border-radius(globals.$ion-border-radius-400);
|
|
||||||
@include globals.padding(globals.$ion-space-100);
|
@include globals.padding(globals.$ion-space-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(.accordion-group-expand-inset.accordion-group-shape-round) {
|
||||||
|
@include globals.border-radius(globals.$ion-border-radius-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.accordion-group-expand-inset.accordion-group-shape-soft) {
|
||||||
|
@include globals.border-radius(globals.$ion-border-radius-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.accordion-group-expand-inset.accordion-group-shape-rectangular) {
|
||||||
|
@include globals.border-radius(globals.$ion-border-radius-0);
|
||||||
|
}
|
||||||
|
@ -60,6 +60,16 @@ export class AccordionGroup implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop() expand: 'compact' | 'inset' = 'compact';
|
@Prop() expand: 'compact' | 'inset' = 'compact';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to `"soft"` for an accordion group with slightly rounded corners,
|
||||||
|
* `"round"` for an accordion group with fully rounded corners, or
|
||||||
|
* `"rectangular"` for an accordion group without rounded corners.
|
||||||
|
*
|
||||||
|
* Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
|
||||||
|
* Only applies when `expand` is set to `"inset"`.
|
||||||
|
*/
|
||||||
|
@Prop() shape?: 'soft' | 'round' | 'rectangular';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when the value property has changed as a result of a user action such as a click.
|
* Emitted when the value property has changed as a result of a user action such as a click.
|
||||||
*
|
*
|
||||||
@ -278,9 +288,26 @@ export class AccordionGroup implements ComponentInterface {
|
|||||||
return Array.from(this.el.querySelectorAll(':scope > ion-accordion')) as HTMLIonAccordionElement[];
|
return Array.from(this.el.querySelectorAll(':scope > ion-accordion')) as HTMLIonAccordionElement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getShape(): string | undefined {
|
||||||
|
const theme = getIonTheme(this);
|
||||||
|
const { shape } = this;
|
||||||
|
|
||||||
|
// TODO(ROU-11328): Remove theme check when shapes are defined for all themes.
|
||||||
|
if (theme !== 'ionic') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape === undefined) {
|
||||||
|
return 'round';
|
||||||
|
}
|
||||||
|
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { disabled, readonly, expand } = this;
|
const { disabled, readonly, expand } = this;
|
||||||
const theme = getIonTheme(this);
|
const theme = getIonTheme(this);
|
||||||
|
const shape = this.getShape();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
@ -289,6 +316,7 @@ export class AccordionGroup implements ComponentInterface {
|
|||||||
'accordion-group-disabled': disabled,
|
'accordion-group-disabled': disabled,
|
||||||
'accordion-group-readonly': readonly,
|
'accordion-group-readonly': readonly,
|
||||||
[`accordion-group-expand-${expand}`]: true,
|
[`accordion-group-expand-${expand}`]: true,
|
||||||
|
[`accordion-group-shape-${shape}`]: shape !== undefined,
|
||||||
}}
|
}}
|
||||||
role="presentation"
|
role="presentation"
|
||||||
>
|
>
|
||||||
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,47 @@
|
|||||||
|
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: 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>
|
||||||
|
|
||||||
|
<ion-accordion-group value="first" expand="inset" shape="${shape}">
|
||||||
|
<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-shape-${shape}`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.7 KiB |
135
core/src/components/accordion-group/test/shape/index.html
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Accordion Group - 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 Group - 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">
|
||||||
|
<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">
|
||||||
|
<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">
|
||||||
|
<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">
|
||||||
|
<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>
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
@ -30,14 +30,14 @@ export declare interface IonAccordion extends Components.IonAccordion {}
|
|||||||
|
|
||||||
|
|
||||||
@ProxyCmp({
|
@ProxyCmp({
|
||||||
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'theme', 'value']
|
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'shape', 'theme', 'value']
|
||||||
})
|
})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-accordion-group',
|
selector: 'ion-accordion-group',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: '<ng-content></ng-content>',
|
template: '<ng-content></ng-content>',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'theme', 'value'],
|
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'shape', 'theme', 'value'],
|
||||||
})
|
})
|
||||||
export class IonAccordionGroup {
|
export class IonAccordionGroup {
|
||||||
protected el: HTMLElement;
|
protected el: HTMLElement;
|
||||||
|
@ -103,14 +103,14 @@ export declare interface IonAccordion extends Components.IonAccordion {}
|
|||||||
|
|
||||||
@ProxyCmp({
|
@ProxyCmp({
|
||||||
defineCustomElementFn: defineIonAccordionGroup,
|
defineCustomElementFn: defineIonAccordionGroup,
|
||||||
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'theme', 'value']
|
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'shape', 'theme', 'value']
|
||||||
})
|
})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-accordion-group',
|
selector: 'ion-accordion-group',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: '<ng-content></ng-content>',
|
template: '<ng-content></ng-content>',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'theme', 'value'],
|
inputs: ['animated', 'disabled', 'expand', 'mode', 'multiple', 'readonly', 'shape', 'theme', 'value'],
|
||||||
standalone: true
|
standalone: true
|
||||||
})
|
})
|
||||||
export class IonAccordionGroup {
|
export class IonAccordionGroup {
|
||||||
|
@ -97,6 +97,7 @@ export const IonAccordionGroup = /*@__PURE__*/ defineContainer<JSX.IonAccordionG
|
|||||||
'disabled',
|
'disabled',
|
||||||
'readonly',
|
'readonly',
|
||||||
'expand',
|
'expand',
|
||||||
|
'shape',
|
||||||
'ionChange',
|
'ionChange',
|
||||||
'ionValueChange'
|
'ionValueChange'
|
||||||
],
|
],
|
||||||
|