Skip to content
Merged
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
6 changes: 6 additions & 0 deletions core/src/components/segment-content/segment-content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

width: 100%;

// Workaround for a Safari/WebKit bug where flexbox children with dynamic
// height (e.g., height: fit-content) are not included in the scrollable area
// when using horizontal scrolling. This is needed to make the segment view
// scroll to the correct content.
min-height: 1px;

overflow-y: scroll;

/* Hide scrollbar in Firefox */
Expand Down
75 changes: 75 additions & 0 deletions core/src/components/segment-view/test/dynamic-height/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Segment View - Dynamic Height</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>

<style>
ion-segment-content {
display: flex;
align-items: center;
justify-content: center;
height: fit-content;
}

ion-segment-content:nth-of-type(1) {
background: lightpink;
}
ion-segment-content:nth-of-type(2) {
background: lightblue;
}
ion-segment-content:nth-of-type(3) {
background: lightgreen;
}
</style>
</head>

<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Segment View - Dynamic Height</ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-segment>
<ion-segment-button value="first" content-id="first">
<ion-label>First</ion-label>
</ion-segment-button>
<ion-segment-button value="second" content-id="second">
<ion-label>Second</ion-label>
</ion-segment-button>
<ion-segment-button value="third" content-id="third">
<ion-label>Third</ion-label>
</ion-segment-button>
</ion-segment>
<ion-segment-view>
<ion-segment-content id="first">
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora
quaeritis. Summus brains sit, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris.
Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat
cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo
sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis
go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv
</ion-segment-content>
<ion-segment-content id="second">
<ion-input value="" label="Email"></ion-input>
</ion-segment-content>
<ion-segment-content id="third">
<ion-img class="img-part" src="https://picsum.photos/200/300"></ion-img>
</ion-segment-content>
</ion-segment-view>
</ion-content>
</ion-app>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* This behavior does not vary across modes/directions
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('segment-view: dynamic height'), () => {
test('should show the third content when clicking the third button', async ({ page, skip }) => {
// Skip this test on Chrome and Firefox
skip.browser('firefox', 'Original issue only happens on Safari.');
skip.browser('chromium', 'Original issue only happens on Safari.');

await page.setContent(
`
<style>
ion-segment-content {
display: flex;
align-items: center;
justify-content: center;
height: fit-content;
}
</style>

<ion-segment>
<ion-segment-button value="first" content-id="first">
<ion-label>First</ion-label>
</ion-segment-button>
<ion-segment-button value="second" content-id="second">
<ion-label>Second</ion-label>
</ion-segment-button>
<ion-segment-button value="third" content-id="third">
<ion-label>Third</ion-label>
</ion-segment-button>
</ion-segment>
<ion-segment-view>
<ion-segment-content id="first">
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora
quaeritis. Summus brains sit, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum
mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus
comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The
voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum
defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv
</ion-segment-content>
<ion-segment-content id="second">
<ion-input value="" label="Email"></ion-input>
</ion-segment-content>
<ion-segment-content id="third">
<ion-img class="img-part" src="https://picsum.photos/200/300"></ion-img>
</ion-segment-content>
</ion-segment-view>
`,
config
);

// Click the third button
await page.locator('ion-segment-button[value="third"]').click();

// Wait for the content to be scrolled
await page.waitForChanges();

// Wait for the image to load and be visible
const imgLocator = page.locator('ion-segment-content#third ion-img');
await imgLocator.waitFor({ state: 'visible', timeout: 10000 });

// Wait for any layout adjustments
await page.waitForChanges();

// Check that the third content is visible
const segmentView = page.locator('ion-segment-view');
const thirdContent = page.locator('ion-segment-content#third');

const viewBox = await segmentView.boundingBox();
const contentBox = await thirdContent.boundingBox();

if (!viewBox || !contentBox) throw new Error('Bounding box not found');

// Allow a small tolerance to account for subpixel rendering,
// scrollbars, or layout rounding differences
const tolerance = 10;
expect(contentBox.x).toBeGreaterThanOrEqual(viewBox.x);
expect(contentBox.x + contentBox.width).toBeLessThanOrEqual(viewBox.x + viewBox.width + tolerance);
});
});
});
Loading