Skip to content

merge release-8.6.1 #30476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 11, 2025
Merged
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
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -120,9 +120,13 @@ jobs:
-d '{
"path": [
"/npm/@ionic/core@6/dist/ionic/ionic.esm.js",
"/npm/@ionic/core@7/dist/ionic/ionic.esm.js",
"/npm/@ionic/core@8/dist/ionic/ionic.esm.js",
"/npm/@ionic/core@latest/dist/ionic/ionic.esm.js",
"/npm/@ionic/core@next/dist/ionic/ionic.esm.js",
"/npm/@ionic/core@6/css/ionic.bundle.css",
"/npm/@ionic/core@7/css/ionic.bundle.css",
"/npm/@ionic/core@8/css/ionic.bundle.css",
"/npm/@ionic/core@latest/css/ionic.bundle.css"
"/npm/@ionic/core@next/css/ionic.bundle.css"
]}'
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [8.6.1](https://github.com/ionic-team/ionic-framework/compare/v8.6.0...v8.6.1) (2025-06-11)


### Bug Fixes

* **item-sliding:** check for side attribute to avoid an `undefined` value ([#29845](https://github.com/ionic-team/ionic-framework/issues/29845)) ([c38aa07](https://github.com/ionic-team/ionic-framework/commit/c38aa07cf8bfab200b3c071328d893bd1627cde7)), closes [#29499](https://github.com/ionic-team/ionic-framework/issues/29499)
* **modal:** reset footer positioning after content drag and multi-footer support ([#30470](https://github.com/ionic-team/ionic-framework/issues/30470)) ([071b414](https://github.com/ionic-team/ionic-framework/commit/071b414a00f4497ed0baa1431f0bee4b3c7c13fb)), closes [#30468](https://github.com/ionic-team/ionic-framework/issues/30468)





# [8.6.0](https://github.com/ionic-team/ionic-framework/compare/v8.5.9...v8.6.0) (2025-06-04)


12 changes: 12 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [8.6.1](https://github.com/ionic-team/ionic-framework/compare/v8.6.0...v8.6.1) (2025-06-11)


### Bug Fixes

* **item-sliding:** check for side attribute to avoid an `undefined` value ([#29845](https://github.com/ionic-team/ionic-framework/issues/29845)) ([c38aa07](https://github.com/ionic-team/ionic-framework/commit/c38aa07cf8bfab200b3c071328d893bd1627cde7)), closes [#29499](https://github.com/ionic-team/ionic-framework/issues/29499)
* **modal:** reset footer positioning after content drag and multi-footer support ([#30470](https://github.com/ionic-team/ionic-framework/issues/30470)) ([071b414](https://github.com/ionic-team/ionic-framework/commit/071b414a00f4497ed0baa1431f0bee4b3c7c13fb)), closes [#30468](https://github.com/ionic-team/ionic-framework/issues/30468)





# [8.6.0](https://github.com/ionic-team/ionic-framework/compare/v8.5.9...v8.6.0) (2025-06-04)


34 changes: 17 additions & 17 deletions core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "8.6.0",
"version": "8.6.1",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -36,7 +36,7 @@
"tslib": "^2.1.0"
},
"devDependencies": {
"@axe-core/playwright": "^4.10.1",
"@axe-core/playwright": "^4.10.2",
"@capacitor/core": "^7.0.0",
"@capacitor/haptics": "^7.0.0",
"@capacitor/keyboard": "^7.0.0",
3 changes: 2 additions & 1 deletion core/src/components/fab/test/custom-size/fab.e2e.ts
Original file line number Diff line number Diff line change
@@ -6,7 +6,8 @@ import { configs, test, Viewports } from '@utils/test/playwright';
*/
configs({ modes: ['ios'] }).forEach(({ title, config, screenshot }) => {
test.describe(title('fab: custom size'), () => {
test('should position fabs correctly with custom sizes', async ({ page }) => {
// TODO(FW-6587): Remove skip once the flaky test is fixed
test.skip('should position fabs correctly with custom sizes', async ({ page }) => {
await page.goto(`/src/components/fab/test/custom-size`, config);

await page.setViewportSize(Viewports.tablet.landscape);
2 changes: 1 addition & 1 deletion core/src/components/item-sliding/item-sliding.tsx
Original file line number Diff line number Diff line change
@@ -263,7 +263,7 @@ export class ItemSliding implements ComponentInterface {
// eslint-disable-next-line custom-rules/no-component-on-ready-method
const option = (item as any).componentOnReady !== undefined ? await item.componentOnReady() : item;

const side = isEndSide(option.side) ? 'end' : 'start';
const side = isEndSide(option.side ?? option.getAttribute('side')) ? 'end' : 'start';

if (side === 'start') {
this.leftOptions = option;
139 changes: 85 additions & 54 deletions core/src/components/modal/gestures/sheet.ts
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@ export const createSheetGesture = (
let offset = 0;
let canDismissBlocksGesture = false;
let cachedScrollEl: HTMLElement | null = null;
let cachedFooterEl: HTMLIonFooterElement | null = null;
let cachedFooterEls: HTMLIonFooterElement[] | null = null;
let cachedFooterYPosition: number | null = null;
let currentFooterState: 'moving' | 'stationary' | null = null;
const canDismissMaxStep = 0.95;
@@ -126,9 +126,9 @@ export const createSheetGesture = (
* @param newPosition Whether the footer is in a moving or stationary position.
*/
const swapFooterPosition = (newPosition: 'moving' | 'stationary') => {
if (!cachedFooterEl) {
cachedFooterEl = baseEl.querySelector('ion-footer') as HTMLIonFooterElement | null;
if (!cachedFooterEl) {
if (!cachedFooterEls) {
cachedFooterEls = Array.from(baseEl.querySelectorAll('ion-footer'));
if (!cachedFooterEls.length) {
return;
}
}
@@ -137,57 +137,80 @@ export const createSheetGesture = (

currentFooterState = newPosition;
if (newPosition === 'stationary') {
// Reset positioning styles to allow normal document flow
cachedFooterEl.classList.remove('modal-footer-moving');
cachedFooterEl.style.removeProperty('position');
cachedFooterEl.style.removeProperty('width');
cachedFooterEl.style.removeProperty('height');
cachedFooterEl.style.removeProperty('top');
cachedFooterEl.style.removeProperty('left');
page?.style.removeProperty('padding-bottom');

// Move to page
page?.appendChild(cachedFooterEl);
cachedFooterEls.forEach((cachedFooterEl) => {
// Reset positioning styles to allow normal document flow
cachedFooterEl.classList.remove('modal-footer-moving');
cachedFooterEl.style.removeProperty('position');
cachedFooterEl.style.removeProperty('width');
cachedFooterEl.style.removeProperty('height');
cachedFooterEl.style.removeProperty('top');
cachedFooterEl.style.removeProperty('left');
page?.style.removeProperty('padding-bottom');

// Move to page
page?.appendChild(cachedFooterEl);
});
} else {
// Get both the footer and document body positions
const cachedFooterElRect = cachedFooterEl.getBoundingClientRect();
const bodyRect = document.body.getBoundingClientRect();

// Add padding to the parent element to prevent content from being hidden
// when the footer is positioned absolutely. This has to be done before we
// make the footer absolutely positioned or we may accidentally cause the
// sheet to scroll.
const footerHeight = cachedFooterEl.clientHeight;
page?.style.setProperty('padding-bottom', `${footerHeight}px`);

// Apply positioning styles to keep footer at bottom
cachedFooterEl.classList.add('modal-footer-moving');

// Calculate absolute position relative to body
// We need to subtract the body's offsetTop to get true position within document.body
const absoluteTop = cachedFooterElRect.top - bodyRect.top;
const absoluteLeft = cachedFooterElRect.left - bodyRect.left;

// Capture the footer's current dimensions and hard code them during the drag
cachedFooterEl.style.setProperty('position', 'absolute');
cachedFooterEl.style.setProperty('width', `${cachedFooterEl.clientWidth}px`);
cachedFooterEl.style.setProperty('height', `${cachedFooterEl.clientHeight}px`);
cachedFooterEl.style.setProperty('top', `${absoluteTop}px`);
cachedFooterEl.style.setProperty('left', `${absoluteLeft}px`);

// Also cache the footer Y position, which we use to determine if the
// sheet has been moved below the footer. When that happens, we need to swap
// the position back so it will collapse correctly.
cachedFooterYPosition = absoluteTop;
// If there's a toolbar, we need to combine the toolbar height with the footer position
// because the toolbar moves with the drag handle, so when it starts overlapping the footer,
// we need to account for that.
const toolbar = baseEl.querySelector('ion-toolbar') as HTMLIonToolbarElement | null;
if (toolbar) {
cachedFooterYPosition -= toolbar.clientHeight;
}

document.body.appendChild(cachedFooterEl);
let footerHeights = 0;
cachedFooterEls.forEach((cachedFooterEl, index) => {
// Get both the footer and document body positions
const cachedFooterElRect = cachedFooterEl.getBoundingClientRect();
const bodyRect = document.body.getBoundingClientRect();

// Calculate the total height of all footers
// so we can add padding to the page element
footerHeights += cachedFooterEl.clientHeight;

// Calculate absolute position relative to body
// We need to subtract the body's offsetTop to get true position within document.body
const absoluteTop = cachedFooterElRect.top - bodyRect.top;
const absoluteLeft = cachedFooterElRect.left - bodyRect.left;

// Capture the footer's current dimensions and store them in CSS variables for
// later use when applying absolute positioning.
cachedFooterEl.style.setProperty('--pinned-width', `${cachedFooterEl.clientWidth}px`);
cachedFooterEl.style.setProperty('--pinned-height', `${cachedFooterEl.clientHeight}px`);
cachedFooterEl.style.setProperty('--pinned-top', `${absoluteTop}px`);
cachedFooterEl.style.setProperty('--pinned-left', `${absoluteLeft}px`);

// Only cache the first footer's Y position
// This is used to determine if the sheet has been moved below the footer
// and needs to be swapped back to stationary so it collapses correctly.
if (index === 0) {
cachedFooterYPosition = absoluteTop;
// If there's a header, we need to combine the header height with the footer position
// because the header moves with the drag handle, so when it starts overlapping the footer,
// we need to account for that.
const header = baseEl.querySelector('ion-header') as HTMLIonHeaderElement | null;
if (header) {
cachedFooterYPosition -= header.clientHeight;
}
}
});

// Apply the pinning of styles after we've calculated everything
// so that we don't cause layouts to shift while calculating the footer positions.
// Otherwise, with multiple footers we'll end up capturing the wrong positions.
cachedFooterEls.forEach((cachedFooterEl) => {
// Add padding to the parent element to prevent content from being hidden
// when the footer is positioned absolutely. This has to be done before we
// make the footer absolutely positioned or we may accidentally cause the
// sheet to scroll.
page?.style.setProperty('padding-bottom', `${footerHeights}px`);

// Apply positioning styles to keep footer at bottom
cachedFooterEl.classList.add('modal-footer-moving');

// Apply our preserved styles to pin the footer
cachedFooterEl.style.setProperty('position', 'absolute');
cachedFooterEl.style.setProperty('width', 'var(--pinned-width)');
cachedFooterEl.style.setProperty('height', 'var(--pinned-height)');
cachedFooterEl.style.setProperty('top', 'var(--pinned-top)');
cachedFooterEl.style.setProperty('left', 'var(--pinned-left)');

// Move the element to the body when everything else is done
document.body.appendChild(cachedFooterEl);
});
}
};

@@ -400,6 +423,14 @@ export const createSheetGesture = (
* is not scrolled to the top.
*/
if (!expandToScroll && detail.deltaY <= 0 && cachedScrollEl && cachedScrollEl.scrollTop > 0) {
/**
* If expand to scroll is disabled, we need to make sure we swap the footer position
* back to stationary so that it will collapse correctly if the modal is dismissed without
* dragging (e.g. through a dismiss button).
* This can cause issues if the user has a modal with content that can be dragged, as we'll
* swap to moving on drag and if we don't swap back here then the footer will get stuck.
*/
swapFooterPosition('stationary');
return;
}

3 changes: 2 additions & 1 deletion core/src/components/popover/test/basic/popover.e2e.ts
Original file line number Diff line number Diff line change
@@ -29,7 +29,8 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
await popoverFixture.open('#long-list-popover');
await popoverFixture.screenshot('basic-long-list-popover', screenshot);
});
test('should render no event popover', async () => {
// TODO(FW-6588): Remove skip once the flaky test is fixed
test.skip('should render no event popover', async () => {
await popoverFixture.open('#no-event-popover');
await popoverFixture.screenshot('basic-no-event-popover', screenshot);
});
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -3,5 +3,5 @@
"core",
"packages/*"
],
"version": "8.6.0"
"version": "8.6.1"
}
8 changes: 8 additions & 0 deletions packages/angular-server/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [8.6.1](https://github.com/ionic-team/ionic-framework/compare/v8.6.0...v8.6.1) (2025-06-11)

**Note:** Version bump only for package @ionic/angular-server





# [8.6.0](https://github.com/ionic-team/ionic-framework/compare/v8.5.9...v8.6.0) (2025-06-04)

**Note:** Version bump only for package @ionic/angular-server
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.