fix(list): remove border from last item with item-sliding (#28439)
Issue number: resolves #28435 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> The item in the last item-sliding still has a border in an inset list. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Item in last item-sliding no longer has a border I originally only added `ion-item-sliding:last-of-type ion-item` but I discovered that the original `ion-item:last-child` causes items in item-sliding where the item is the last element in the item-sliding container to not have a border, so the original fix was incomplete. I added comments as to what each line does and why we didn't just do `ion-item:last-child`. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> -------- Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com> --------- Co-authored-by: ionitron <hi@ionicframework.com> Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
@ -19,12 +19,25 @@
|
|||||||
@include border-radius($list-inset-ios-border-radius);
|
@include border-radius($list-inset-ios-border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-ios.list-inset ion-item:last-child {
|
/**
|
||||||
|
* These selectors ensure the last item in the list
|
||||||
|
* has the correct border.
|
||||||
|
* We need to consider the following scenarios:
|
||||||
|
1. The only item in a list.
|
||||||
|
2. The last item in a list as long as it is not the only item.
|
||||||
|
3. The item in the last item-sliding in a list.
|
||||||
|
* Note that we do not select ion-item:last-of-type
|
||||||
|
* because that will cause the borders to disappear on
|
||||||
|
* items in an item-sliding when the item is the last
|
||||||
|
* element in the item-sliding container.
|
||||||
|
*/
|
||||||
|
.list-ios.list-inset ion-item:only-child,
|
||||||
|
.list-ios.list-inset ion-item:not(:only-of-type):last-of-type,
|
||||||
|
.list-ios.list-inset ion-item-sliding:last-of-type ion-item {
|
||||||
--border-width: 0;
|
--border-width: 0;
|
||||||
--inner-border-width: 0;
|
--inner-border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.list-ios.list-inset + ion-list.list-inset {
|
.list-ios.list-inset + ion-list.list-inset {
|
||||||
@include margin(0, null, null, null);
|
@include margin(0, null, null, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,12 +23,50 @@
|
|||||||
@include border-radius($list-inset-md-border-radius);
|
@include border-radius($list-inset-md-border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-md.list-inset ion-item:first-child {
|
/**
|
||||||
|
* These selectors ensure the first item in the list
|
||||||
|
* has the correct radius.
|
||||||
|
* We need to consider the following scenarios:
|
||||||
|
1. The first item in a list as long as it is not the only item.
|
||||||
|
2. The item in the first item-sliding in a list.
|
||||||
|
* Note that we do not select "ion-item-sliding ion-item:first-of-type"
|
||||||
|
* because that will cause the borders to disappear on
|
||||||
|
* items in an item-sliding when the item is the first
|
||||||
|
* element in the item-sliding container.
|
||||||
|
*/
|
||||||
|
.list-md.list-inset ion-item:not(:only-of-type):first-of-type,
|
||||||
|
.list-md.list-inset ion-item-sliding:first-of-type ion-item {
|
||||||
--border-radius: #{$list-inset-md-border-radius $list-inset-md-border-radius 0 0};
|
--border-radius: #{$list-inset-md-border-radius $list-inset-md-border-radius 0 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-md.list-inset ion-item:last-child {
|
/**
|
||||||
--border-radius: #{0 0 $list-inset-md-border-radius, $list-inset-md-border-radius};
|
* These selectors ensure the last item in the list
|
||||||
|
* has the correct radius and border.
|
||||||
|
* We need to consider the following scenarios:
|
||||||
|
1. The last item in a list as long as it is not the only item.
|
||||||
|
2. The item in the last item-sliding in a list.
|
||||||
|
* Note that we do not select "ion-item-sliding ion-item:last-of-type"
|
||||||
|
* because that will cause the borders to disappear on
|
||||||
|
* items in an item-sliding when the item is the last
|
||||||
|
* element in the item-sliding container.
|
||||||
|
*/
|
||||||
|
.list-md.list-inset ion-item:not(:only-of-type):last-of-type,
|
||||||
|
.list-md.list-inset ion-item-sliding:last-of-type ion-item {
|
||||||
|
--border-radius: #{0 0 $list-inset-md-border-radius $list-inset-md-border-radius};
|
||||||
|
--border-width: 0;
|
||||||
|
--inner-border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The only item in a list should have a border radius
|
||||||
|
* on all corners.
|
||||||
|
* We target :only-child instead of :only-of-type
|
||||||
|
* otherwise borders will disappear on items inside of
|
||||||
|
* ion-item-sliding because the item will be the only
|
||||||
|
* one of its type inside of the ion-item-sliding group.
|
||||||
|
*/
|
||||||
|
.list-md.list-inset ion-item:only-child {
|
||||||
|
--border-radius: #{$list-inset-md-border-radius};
|
||||||
--border-width: 0;
|
--border-width: 0;
|
||||||
--inner-border-width: 0;
|
--inner-border-width: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,3 +26,162 @@ configs().forEach(({ title, screenshot, config }) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Padding and border color ensures the bottom border can be easily seen if it regresses.
|
||||||
|
* The background color ensures that any border radius values can be seen.
|
||||||
|
*/
|
||||||
|
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||||
|
test.describe(title('list: lines with children'), () => {
|
||||||
|
test('only item in inset list should not have line', async ({ page }) => {
|
||||||
|
test.info().annotations.push({
|
||||||
|
type: 'issue',
|
||||||
|
description: 'https://github.com/ionic-team/ionic-framework/issues/28435',
|
||||||
|
});
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<style>
|
||||||
|
#container {
|
||||||
|
padding: 10px;
|
||||||
|
background: #0088cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item {
|
||||||
|
--border-color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="container">
|
||||||
|
<ion-list inset="true">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 0</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const container = page.locator('#container');
|
||||||
|
|
||||||
|
await expect(container).toHaveScreenshot(screenshot('inset-list-only-item-no-lines'));
|
||||||
|
});
|
||||||
|
test('last item in inset list with end options should not have line', async ({ page }) => {
|
||||||
|
test.info().annotations.push({
|
||||||
|
type: 'issue',
|
||||||
|
description: 'https://github.com/ionic-team/ionic-framework/issues/28435',
|
||||||
|
});
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<style>
|
||||||
|
#container {
|
||||||
|
padding: 10px;
|
||||||
|
background: #0088cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item {
|
||||||
|
--border-color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="container">
|
||||||
|
<ion-list inset="true">
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 0</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options slot="end">
|
||||||
|
<ion-item-option color="warning">
|
||||||
|
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||||
|
</ion-item-option>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 1</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options slot="end">
|
||||||
|
<ion-item-option color="warning">
|
||||||
|
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||||
|
</ion-item-option>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 2</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options slot="end">
|
||||||
|
<ion-item-option color="warning">
|
||||||
|
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||||
|
</ion-item-option>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
</ion-list>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const container = page.locator('#container');
|
||||||
|
|
||||||
|
await expect(container).toHaveScreenshot(screenshot('inset-list-end-options-no-lines'));
|
||||||
|
});
|
||||||
|
test('last item in inset list with start options should not have line', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<style>
|
||||||
|
#container {
|
||||||
|
padding: 10px;
|
||||||
|
background: #0088cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item {
|
||||||
|
--border-color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="container">
|
||||||
|
<ion-list inset="true">
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item-options slot="start">
|
||||||
|
<ion-item-option color="warning">
|
||||||
|
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||||
|
</ion-item-option>
|
||||||
|
</ion-item-options>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 0</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item-options slot="start">
|
||||||
|
<ion-item-option color="warning">
|
||||||
|
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||||
|
</ion-item-option>
|
||||||
|
</ion-item-options>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 1</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item-options slot="start">
|
||||||
|
<ion-item-option color="warning">
|
||||||
|
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||||
|
</ion-item-option>
|
||||||
|
</ion-item-options>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Item 2</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-sliding>
|
||||||
|
</ion-list>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const container = page.locator('#container');
|
||||||
|
|
||||||
|
await expect(container).toHaveScreenshot(screenshot('inset-list-start-options-no-lines'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |