Skip to content

Commit 33b834a

Browse files
committed
Merge branch 'feature-8.8' into FW-6582
2 parents de12c69 + ef73476 commit 33b834a

21 files changed

Lines changed: 657 additions & 73 deletions

core/api.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,9 @@ ion-item,css-prop,--ripple-color,ios
939939
ion-item,css-prop,--ripple-color,md
940940
ion-item,css-prop,--transition,ios
941941
ion-item,css-prop,--transition,md
942+
ion-item,part,container
942943
ion-item,part,detail-icon
944+
ion-item,part,inner
943945
ion-item,part,native
944946

945947
ion-item-divider,shadow
@@ -966,6 +968,8 @@ ion-item-divider,css-prop,--padding-start,ios
966968
ion-item-divider,css-prop,--padding-start,md
967969
ion-item-divider,css-prop,--padding-top,ios
968970
ion-item-divider,css-prop,--padding-top,md
971+
ion-item-divider,part,container
972+
ion-item-divider,part,inner
969973

970974
ion-item-group,none
971975

@@ -983,6 +987,8 @@ ion-item-option,css-prop,--background,ios
983987
ion-item-option,css-prop,--background,md
984988
ion-item-option,css-prop,--color,ios
985989
ion-item-option,css-prop,--color,md
990+
ion-item-option,part,container
991+
ion-item-option,part,inner
986992
ion-item-option,part,native
987993

988994
ion-item-options,none
@@ -1027,6 +1033,7 @@ ion-list-header,css-prop,--color,ios
10271033
ion-list-header,css-prop,--color,md
10281034
ion-list-header,css-prop,--inner-border-width,ios
10291035
ion-list-header,css-prop,--inner-border-width,md
1036+
ion-list-header,part,inner
10301037

10311038
ion-loading,scoped
10321039
ion-loading,prop,animated,boolean,true,false,false

core/src/components/item-divider/item-divider.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import type { Color } from '../../interface';
1111
* @slot - Content is placed between the named slots if provided without a slot.
1212
* @slot start - Content is placed to the left of the divider text in LTR, and to the right in RTL.
1313
* @slot end - Content is placed to the right of the divider text in LTR, and to the left in RTL.
14+
*
15+
* @part inner - The inner wrapper element that arranges the divider content.
16+
* @part container - The wrapper element that contains the default slot.
1417
*/
1518
@Component({
1619
tag: 'ion-item-divider',
@@ -50,8 +53,8 @@ export class ItemDivider implements ComponentInterface {
5053
})}
5154
>
5255
<slot name="start"></slot>
53-
<div class="item-divider-inner">
54-
<div class="item-divider-wrapper">
56+
<div class="item-divider-inner" part="inner">
57+
<div class="item-divider-wrapper" part="container">
5558
<slot></slot>
5659
</div>
5760
<slot name="end"></slot>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
/**
5+
* This behavior does not vary across modes/directions
6+
*/
7+
configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, config }) => {
8+
test.describe(title('item-divider: custom'), () => {
9+
test.describe('CSS shadow parts', () => {
10+
test('should be able to customize inner part', async ({ page }) => {
11+
await page.setContent(
12+
`
13+
<style>
14+
ion-item-divider::part(inner) {
15+
background-color: red;
16+
}
17+
</style>
18+
19+
<ion-item-divider>Divider</ion-item-divider>
20+
`,
21+
config
22+
);
23+
24+
const divider = page.locator('ion-item-divider');
25+
const backgroundColor = await divider.evaluate((el) => {
26+
const shadowRoot = el.shadowRoot;
27+
const inner = shadowRoot?.querySelector('.item-divider-inner');
28+
return inner ? window.getComputedStyle(inner).backgroundColor : '';
29+
});
30+
expect(backgroundColor).toBe('rgb(255, 0, 0)');
31+
});
32+
33+
test('should be able to customize container part', async ({ page }) => {
34+
await page.setContent(
35+
`
36+
<style>
37+
ion-item-divider::part(container) {
38+
background-color: green;
39+
}
40+
</style>
41+
42+
<ion-item-divider>Divider</ion-item-divider>
43+
`,
44+
config
45+
);
46+
47+
const divider = page.locator('ion-item-divider');
48+
const backgroundColor = await divider.evaluate((el) => {
49+
const shadowRoot = el.shadowRoot;
50+
const container = shadowRoot?.querySelector('.item-divider-wrapper');
51+
return container ? window.getComputedStyle(container).backgroundColor : '';
52+
});
53+
expect(backgroundColor).toBe('rgb(0, 128, 0)');
54+
});
55+
});
56+
});
57+
});

core/src/components/item-option/item-option.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import type { Color } from '../../interface';
1717
* @slot end - Content is placed to the right of the option text in LTR, and to the left in RTL.
1818
*
1919
* @part native - The native HTML button or anchor element that wraps all child elements.
20+
* @part inner - The inner wrapper element that arranges the option content.
21+
* @part container - The container element that wraps the start, icon-only, default, and end slots.
2022
*/
2123
@Component({
2224
tag: 'ion-item-option',
@@ -109,9 +111,9 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn
109111
})}
110112
>
111113
<TagType {...attrs} class="button-native" part="native" disabled={disabled}>
112-
<span class="button-inner">
114+
<span class="button-inner" part="inner">
113115
<slot name="top"></slot>
114-
<div class="horizontal-wrapper">
116+
<div class="horizontal-wrapper" part="container">
115117
<slot name="start"></slot>
116118
<slot name="icon-only"></slot>
117119
<slot></slot>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
/**
5+
* This behavior does not vary across modes/directions
6+
*/
7+
configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, config }) => {
8+
test.describe(title('item-option: custom'), () => {
9+
test.describe('CSS shadow parts', () => {
10+
test('should be able to customize native part', async ({ page }) => {
11+
await page.setContent(
12+
`
13+
<style>
14+
ion-item-option::part(native) {
15+
background-color: red;
16+
}
17+
</style>
18+
19+
<ion-item-option>Option</ion-item-option>
20+
`,
21+
config
22+
);
23+
24+
const itemOption = page.locator('ion-item-option');
25+
const backgroundColor = await itemOption.evaluate((el) => {
26+
const shadowRoot = el.shadowRoot;
27+
const native = shadowRoot?.querySelector('.button-native');
28+
return native ? window.getComputedStyle(native).backgroundColor : '';
29+
});
30+
expect(backgroundColor).toBe('rgb(255, 0, 0)');
31+
});
32+
33+
test('should be able to customize inner part', async ({ page }) => {
34+
await page.setContent(
35+
`
36+
<style>
37+
ion-item-option::part(inner) {
38+
background-color: green;
39+
}
40+
</style>
41+
42+
<ion-item-option>Option</ion-item-option>
43+
`,
44+
config
45+
);
46+
47+
const itemOption = page.locator('ion-item-option');
48+
const backgroundColor = await itemOption.evaluate((el) => {
49+
const shadowRoot = el.shadowRoot;
50+
const inner = shadowRoot?.querySelector('.button-inner');
51+
return inner ? window.getComputedStyle(inner).backgroundColor : '';
52+
});
53+
expect(backgroundColor).toBe('rgb(0, 128, 0)');
54+
});
55+
56+
test('should be able to customize container part', async ({ page }) => {
57+
await page.setContent(
58+
`
59+
<style>
60+
ion-item-option::part(container) {
61+
background-color: blue;
62+
}
63+
</style>
64+
65+
<ion-item-option>Option</ion-item-option>
66+
`,
67+
config
68+
);
69+
70+
const itemOption = page.locator('ion-item-option');
71+
const backgroundColor = await itemOption.evaluate((el) => {
72+
const shadowRoot = el.shadowRoot;
73+
const container = shadowRoot?.querySelector('.horizontal-wrapper');
74+
return container ? window.getComputedStyle(container).backgroundColor : '';
75+
});
76+
expect(backgroundColor).toBe('rgb(0, 0, 255)');
77+
});
78+
});
79+
});
80+
});

core/src/components/item/item.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import type { RouterDirection } from '../router/utils/interface';
1818
* @slot end - Content is placed to the right of the item text in LTR, and to the left in RTL.
1919
*
2020
* @part native - The native HTML button, anchor or div element that wraps all child elements.
21+
* @part inner - The inner wrapper element that arranges the item content.
22+
* @part container - The wrapper element that contains the default slot.
2123
* @part detail-icon - The chevron icon for the item. Only applies when `detail="true"`.
2224
*/
2325
@Component({
@@ -390,8 +392,8 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
390392
{...clickFn}
391393
>
392394
<slot name="start" onSlotchange={this.updateInteractivityOnSlotChange}></slot>
393-
<div class="item-inner">
394-
<div class="input-wrapper">
395+
<div class="item-inner" part="inner">
396+
<div class="input-wrapper" part="container">
395397
<slot onSlotchange={this.updateInteractivityOnSlotChange}></slot>
396398
</div>
397399
<slot name="end" onSlotchange={this.updateInteractivityOnSlotChange}></slot>

core/src/components/item/test/css-variables/index.html

Lines changed: 0 additions & 49 deletions
This file was deleted.

core/src/components/item/test/css-variables/item.e2e.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)