Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,9 @@ ion-item,css-prop,--ripple-color,ios
ion-item,css-prop,--ripple-color,md
ion-item,css-prop,--transition,ios
ion-item,css-prop,--transition,md
ion-item,part,content
ion-item,part,detail-icon
ion-item,part,inner
ion-item,part,native

ion-item-divider,shadow
Expand Down
6 changes: 4 additions & 2 deletions core/src/components/item/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import type { RouterDirection } from '../router/utils/interface';
* @slot end - Content is placed to the right of the item text in LTR, and to the left in RTL.
*
* @part native - The native HTML button, anchor or div element that wraps all child elements.
* @part inner - The inner container element that wraps the item content.
* @part content - The wrapper element that contains the default slot.
* @part detail-icon - The chevron icon for the item. Only applies when `detail="true"`.
*/
@Component({
Expand Down Expand Up @@ -390,8 +392,8 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
{...clickFn}
>
<slot name="start" onSlotchange={this.updateInteractivityOnSlotChange}></slot>
<div class="item-inner">
<div class="input-wrapper">
<div class="item-inner" part="inner">
<div class="input-wrapper" part="content">
<slot onSlotchange={this.updateInteractivityOnSlotChange}></slot>
</div>
<slot name="end" onSlotchange={this.updateInteractivityOnSlotChange}></slot>
Expand Down
49 changes: 0 additions & 49 deletions core/src/components/item/test/css-variables/index.html

This file was deleted.

17 changes: 0 additions & 17 deletions core/src/components/item/test/css-variables/item.e2e.ts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deleted this test because it doesn't do anything except set CSS variables so I added the same check here: https://github.com/ionic-team/ionic-framework/pull/30927/changes#diff-ede714f4c0e943356ae72d2456093d9e6ccc4e6fc86b465f598231be62a3ae8fR111

This file was deleted.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
174 changes: 174 additions & 0 deletions core/src/components/item/test/custom/item.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* This behavior does not vary across modes/directions
*/
configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, config }) => {
test.describe(title('item: custom'), () => {
test.describe(title('CSS shadow parts'), () => {
test('should be able to customize native part', async ({ page }) => {
await page.setContent(
`
<style>
ion-item::part(native) {
background-color: red;
}
</style>

<ion-item>
<ion-label>Item</ion-label>
</ion-item>
`,
config
);

const item = page.locator('ion-item');
const backgroundColor = await item.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const native = shadowRoot?.querySelector('.item-native');
return native ? window.getComputedStyle(native).backgroundColor : '';
});
expect(backgroundColor).toBe('rgb(255, 0, 0)');
});

test('should be able to customize inner part', async ({ page }) => {
await page.setContent(
`
<style>
ion-item::part(inner) {
background-color: green;
}
</style>

<ion-item>
<ion-label>Item</ion-label>
</ion-item>
`,
config
);

const item = page.locator('ion-item');
const backgroundColor = await item.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const inner = shadowRoot?.querySelector('.item-inner');
return inner ? window.getComputedStyle(inner).backgroundColor : '';
});
expect(backgroundColor).toBe('rgb(0, 128, 0)');
});

test('should be able to customize content part', async ({ page }) => {
await page.setContent(
`
<style>
ion-item::part(content) {
background-color: blue;
}
</style>

<ion-item>
<ion-label>Item</ion-label>
</ion-item>
`,
config
);

const item = page.locator('ion-item');
const backgroundColor = await item.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const content = shadowRoot?.querySelector('.input-wrapper');
return content ? window.getComputedStyle(content).backgroundColor : '';
});
expect(backgroundColor).toBe('rgb(0, 0, 255)');
});

test('should be able to customize detail-icon part', async ({ page }) => {
await page.setContent(
`
<style>
ion-item::part(detail-icon) {
background-color: red;
}
</style>

<ion-item detail="true">
<ion-label>Item</ion-label>
</ion-item>
`,
config
);

const item = page.locator('ion-item');
const backgroundColor = await item.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const detailIcon = shadowRoot?.querySelector('.item-detail-icon');
return detailIcon ? window.getComputedStyle(detailIcon).backgroundColor : '';
});
expect(backgroundColor).toBe('rgb(255, 0, 0)');
});
});

test.describe(title('CSS variables'), () => {
test('should be able to customize background using css variables', async ({ page }) => {
await page.setContent(
`
<style>
ion-item {
--background: red;
}
</style>

<ion-item>
<ion-label>Item</ion-label>
</ion-item>
`,
config
);

const item = page.locator('ion-item');
const backgroundColor = await item.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const native = shadowRoot?.querySelector('.item-native');
return native ? window.getComputedStyle(native).backgroundColor : '';
});
expect(backgroundColor).toBe('rgb(255, 0, 0)');
});

test('should be able to customize padding using css variables', async ({ page }) => {
await page.setContent(
`
<style>
ion-item {
--padding-top: 20px;
--padding-bottom: 20px;
--padding-start: 10px;
--padding-end: 10px;
}
</style>

<ion-item>
<ion-label>Item</ion-label>
</ion-item>
`,
config
);

const item = page.locator('ion-item');
const paddingValues = await item.evaluate((el) => {
const shadowRoot = el.shadowRoot;
const native = shadowRoot?.querySelector('.item-native');
return {
paddingTop: native ? window.getComputedStyle(native).paddingTop : '',
paddingBottom: native ? window.getComputedStyle(native).paddingBottom : '',
paddingStart: native ? window.getComputedStyle(native).paddingLeft : '',
paddingEnd: native ? window.getComputedStyle(native).paddingRight : '',
};
});
expect(paddingValues.paddingTop).toBe('20px');
expect(paddingValues.paddingBottom).toBe('20px');
expect(paddingValues.paddingStart).toBe('10px');
expect(paddingValues.paddingEnd).toBe('10px');
});
});
});
});
Loading