mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 02:31:34 +08:00
chore(merge): merging main into next
This commit is contained in:
23
.github/workflows/conventional-commit.yml
vendored
23
.github/workflows/conventional-commit.yml
vendored
@ -9,12 +9,29 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate PR title
|
||||
if: |
|
||||
!contains(github.event.pull_request.title, 'release') &&
|
||||
!contains(github.event.pull_request.title, 'chore')
|
||||
uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# Configure that a scope must always be provided.
|
||||
requireScope: true
|
||||
# Configure allowed commit types
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
build
|
||||
ci
|
||||
revert
|
||||
release
|
||||
chore
|
||||
# Configure additional validation for the subject based on a regex.
|
||||
# This example ensures the subject doesn't start with an uppercase character.
|
||||
subjectPattern: ^(?![A-Z]).+$
|
||||
@ -24,9 +41,3 @@ jobs:
|
||||
# within the message.
|
||||
subjectPatternError: |
|
||||
The subject "{subject}" found in the pull request title "{title}" didn't match the configured pattern. Please ensure that the subject doesn't start with an uppercase character.
|
||||
# If the PR contains one of these newline-delimited labels, the
|
||||
# validation is skipped. If you want to rerun the validation when
|
||||
# labels change, you might want to use the `labeled` and `unlabeled`
|
||||
# event triggers in your workflow.
|
||||
ignoreLabels: |
|
||||
release
|
||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.6.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **modal:** support iOS card view transitions for viewport changes ([#30520](https://github.com/ionic-team/ionic-framework/issues/30520)) ([0fd9e82](https://github.com/ionic-team/ionic-framework/commit/0fd9e824508333a53175d7da5f681fc3126a2394)), closes [#30296](https://github.com/ionic-team/ionic-framework/issues/30296)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
|
||||
|
@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.6.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **modal:** support iOS card view transitions for viewport changes ([#30520](https://github.com/ionic-team/ionic-framework/issues/30520)) ([0fd9e82](https://github.com/ionic-team/ionic-framework/commit/0fd9e824508333a53175d7da5f681fc3126a2394)), closes [#30296](https://github.com/ionic-team/ionic-framework/issues/30296)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
|
||||
|
2
core/package-lock.json
generated
2
core/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('item-sliding: async'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@ -35,5 +38,85 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
|
||||
await expect(itemSlidingEl).toHaveClass(/item-sliding-active-slide/);
|
||||
});
|
||||
|
||||
// NOTE: This test uses the CDN version of Ionic.
|
||||
// If this test fails, it is likely due to a regression in the published package.
|
||||
test('should not throw errors when adding multiple items with side="end" using the Ionic CDN', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/29499',
|
||||
});
|
||||
|
||||
const errors: string[] = [];
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') {
|
||||
errors.push(msg.text());
|
||||
}
|
||||
});
|
||||
page.on('pageerror', (error) => {
|
||||
errors.push(error.message);
|
||||
});
|
||||
|
||||
// This issue only happens when using a CDN version of Ionic
|
||||
// so we need to use the CDN by passing the `importIonicFromCDN` option
|
||||
// to setContent.
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Item Sliding</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button id="addItem" onclick="addItem()">ADD ITEM</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-list id="list"></ion-list>
|
||||
</ion-content>
|
||||
|
||||
<script>
|
||||
let itemList = [];
|
||||
function generateItem() {
|
||||
const currentItem = itemList.length + 1;
|
||||
const item = \`
|
||||
<ion-item-sliding>
|
||||
<ion-item>
|
||||
<ion-label>Sliding Item \${currentItem}</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options side="end">
|
||||
<ion-item-option>Delete</ion-item-option>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
\`;
|
||||
itemList.push(item);
|
||||
return item;
|
||||
}
|
||||
function addItem() {
|
||||
const list = document.getElementById('list');
|
||||
list.innerHTML += generateItem();
|
||||
const currentItem = itemList.length;
|
||||
}
|
||||
</script>
|
||||
`,
|
||||
{ ...config, importIonicFromCDN: true }
|
||||
);
|
||||
|
||||
// Click the button enough times to reproduce the issue
|
||||
const addButton = page.locator('#addItem');
|
||||
await addButton.click();
|
||||
await addButton.click();
|
||||
await addButton.click();
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
// Check that the items have been added
|
||||
const items = page.locator('ion-item-sliding');
|
||||
expect(await items.count()).toBe(3);
|
||||
|
||||
// Check that no errors have been logged
|
||||
expect(errors.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -48,7 +48,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts: ModalAnimationOptio
|
||||
}
|
||||
|
||||
if (presentingEl) {
|
||||
const isMobile = window.innerWidth < 768;
|
||||
const isPortrait = window.innerWidth < 768;
|
||||
const hasCardModal =
|
||||
presentingEl.tagName === 'ION-MODAL' && (presentingEl as HTMLIonModalElement).presentingElement !== undefined;
|
||||
const presentingElRoot = getElementRoot(presentingEl);
|
||||
@ -61,7 +61,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts: ModalAnimationOptio
|
||||
|
||||
const bodyEl = document.body;
|
||||
|
||||
if (isMobile) {
|
||||
if (isPortrait) {
|
||||
/**
|
||||
* Fallback for browsers that does not support `max()` (ex: Firefox)
|
||||
* No need to worry about statusbar padding since engines like Gecko
|
||||
|
@ -35,7 +35,7 @@ export const iosLeaveAnimation = (baseEl: HTMLElement, opts: ModalAnimationOptio
|
||||
.addAnimation(wrapperAnimation);
|
||||
|
||||
if (presentingEl) {
|
||||
const isMobile = window.innerWidth < 768;
|
||||
const isPortrait = window.innerWidth < 768;
|
||||
const hasCardModal =
|
||||
presentingEl.tagName === 'ION-MODAL' && (presentingEl as HTMLIonModalElement).presentingElement !== undefined;
|
||||
const presentingElRoot = getElementRoot(presentingEl);
|
||||
@ -61,7 +61,7 @@ export const iosLeaveAnimation = (baseEl: HTMLElement, opts: ModalAnimationOptio
|
||||
|
||||
const bodyEl = document.body;
|
||||
|
||||
if (isMobile) {
|
||||
if (isPortrait) {
|
||||
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
||||
const modalTransform = hasCardModal ? '-10px' : transformOffset;
|
||||
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
||||
|
198
core/src/components/modal/animations/ios.transition.ts
Normal file
198
core/src/components/modal/animations/ios.transition.ts
Normal file
@ -0,0 +1,198 @@
|
||||
import { createAnimation } from '@utils/animation/animation';
|
||||
import { getElementRoot } from '@utils/helpers';
|
||||
|
||||
import type { Animation } from '../../../interface';
|
||||
import { SwipeToCloseDefaults } from '../gestures/swipe-to-close';
|
||||
import type { ModalAnimationOptions } from '../modal-interface';
|
||||
|
||||
/**
|
||||
* Transition animation from portrait view to landscape view
|
||||
* This handles the case where a card modal is open in portrait view
|
||||
* and the user switches to landscape view
|
||||
*/
|
||||
export const portraitToLandscapeTransition = (
|
||||
baseEl: HTMLElement,
|
||||
opts: ModalAnimationOptions,
|
||||
duration = 300
|
||||
): Animation => {
|
||||
const { presentingEl } = opts;
|
||||
|
||||
if (!presentingEl) {
|
||||
// No transition needed for non-card modals
|
||||
return createAnimation('portrait-to-landscape-transition');
|
||||
}
|
||||
|
||||
const presentingElIsCardModal =
|
||||
presentingEl.tagName === 'ION-MODAL' && (presentingEl as HTMLIonModalElement).presentingElement !== undefined;
|
||||
const presentingElRoot = getElementRoot(presentingEl);
|
||||
const bodyEl = document.body;
|
||||
|
||||
const baseAnimation = createAnimation('portrait-to-landscape-transition')
|
||||
.addElement(baseEl)
|
||||
.easing('cubic-bezier(0.32,0.72,0,1)')
|
||||
.duration(duration);
|
||||
|
||||
const presentingAnimation = createAnimation().beforeStyles({
|
||||
transform: 'translateY(0)',
|
||||
'transform-origin': 'top center',
|
||||
overflow: 'hidden',
|
||||
});
|
||||
|
||||
if (!presentingElIsCardModal) {
|
||||
// The presenting element is not a card modal, so we do not
|
||||
// need to care about layering and modal-specific styles.
|
||||
const root = getElementRoot(baseEl);
|
||||
const wrapperAnimation = createAnimation()
|
||||
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow')!)
|
||||
.fromTo('opacity', '1', '1'); // Keep wrapper visible in landscape
|
||||
|
||||
const backdropAnimation = createAnimation()
|
||||
.addElement(root.querySelector('ion-backdrop')!)
|
||||
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
|
||||
|
||||
// Animate presentingEl from portrait state back to normal
|
||||
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
||||
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
||||
const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
||||
|
||||
presentingAnimation
|
||||
.addElement(presentingEl)
|
||||
.afterStyles({
|
||||
transform: 'translateY(0px) scale(1)',
|
||||
'border-radius': '0px',
|
||||
})
|
||||
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', ''))
|
||||
.fromTo('transform', fromTransform, 'translateY(0px) scale(1)')
|
||||
.fromTo('filter', 'contrast(0.85)', 'contrast(1)')
|
||||
.fromTo('border-radius', '10px 10px 0 0', '0px');
|
||||
|
||||
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
|
||||
} else {
|
||||
// The presenting element is a card modal, so we do
|
||||
// need to care about layering and modal-specific styles.
|
||||
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
||||
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
||||
const toTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
||||
|
||||
presentingAnimation
|
||||
.addElement(presentingElRoot.querySelector('.modal-wrapper')!)
|
||||
.afterStyles({
|
||||
transform: toTransform,
|
||||
})
|
||||
.fromTo('transform', fromTransform, toTransform)
|
||||
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
|
||||
|
||||
const shadowAnimation = createAnimation()
|
||||
.addElement(presentingElRoot.querySelector('.modal-shadow')!)
|
||||
.afterStyles({
|
||||
transform: toTransform,
|
||||
})
|
||||
.fromTo('opacity', '0', '0') // Shadow stays hidden in landscape for card modals
|
||||
.fromTo('transform', fromTransform, toTransform);
|
||||
|
||||
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
|
||||
}
|
||||
|
||||
return baseAnimation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transition animation from landscape view to portrait view
|
||||
* This handles the case where a card modal is open in landscape view
|
||||
* and the user switches to portrait view
|
||||
*/
|
||||
export const landscapeToPortraitTransition = (
|
||||
baseEl: HTMLElement,
|
||||
opts: ModalAnimationOptions,
|
||||
duration = 300
|
||||
): Animation => {
|
||||
const { presentingEl } = opts;
|
||||
|
||||
if (!presentingEl) {
|
||||
// No transition needed for non-card modals
|
||||
return createAnimation('landscape-to-portrait-transition');
|
||||
}
|
||||
|
||||
const presentingElIsCardModal =
|
||||
presentingEl.tagName === 'ION-MODAL' && (presentingEl as HTMLIonModalElement).presentingElement !== undefined;
|
||||
const presentingElRoot = getElementRoot(presentingEl);
|
||||
const bodyEl = document.body;
|
||||
|
||||
const baseAnimation = createAnimation('landscape-to-portrait-transition')
|
||||
.addElement(baseEl)
|
||||
.easing('cubic-bezier(0.32,0.72,0,1)')
|
||||
.duration(duration);
|
||||
|
||||
const presentingAnimation = createAnimation().beforeStyles({
|
||||
transform: 'translateY(0)',
|
||||
'transform-origin': 'top center',
|
||||
overflow: 'hidden',
|
||||
});
|
||||
|
||||
if (!presentingElIsCardModal) {
|
||||
// The presenting element is not a card modal, so we do not
|
||||
// need to care about layering and modal-specific styles.
|
||||
const root = getElementRoot(baseEl);
|
||||
const wrapperAnimation = createAnimation()
|
||||
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow')!)
|
||||
.fromTo('opacity', '1', '1'); // Keep wrapper visible
|
||||
|
||||
const backdropAnimation = createAnimation()
|
||||
.addElement(root.querySelector('ion-backdrop')!)
|
||||
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
|
||||
|
||||
// Animate presentingEl from normal state to portrait state
|
||||
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
||||
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
||||
const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
||||
|
||||
presentingAnimation
|
||||
.addElement(presentingEl)
|
||||
.beforeStyles({
|
||||
transform: 'translateY(0px) scale(1)',
|
||||
'transform-origin': 'top center',
|
||||
overflow: 'hidden',
|
||||
})
|
||||
.afterStyles({
|
||||
transform: toTransform,
|
||||
'border-radius': '10px 10px 0 0',
|
||||
filter: 'contrast(0.85)',
|
||||
overflow: 'hidden',
|
||||
'transform-origin': 'top center',
|
||||
})
|
||||
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
|
||||
.keyframes([
|
||||
{ offset: 0, transform: 'translateY(0px) scale(1)', filter: 'contrast(1)', borderRadius: '0px' },
|
||||
{ offset: 0.2, transform: 'translateY(0px) scale(1)', filter: 'contrast(1)', borderRadius: '10px 10px 0 0' },
|
||||
{ offset: 1, transform: toTransform, filter: 'contrast(0.85)', borderRadius: '10px 10px 0 0' },
|
||||
]);
|
||||
|
||||
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
|
||||
} else {
|
||||
// The presenting element is also a card modal, so we need
|
||||
// to handle layering and modal-specific styles.
|
||||
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
||||
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
||||
const toTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
||||
|
||||
presentingAnimation
|
||||
.addElement(presentingElRoot.querySelector('.modal-wrapper')!)
|
||||
.afterStyles({
|
||||
transform: toTransform,
|
||||
})
|
||||
.fromTo('transform', fromTransform, toTransform)
|
||||
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
|
||||
|
||||
const shadowAnimation = createAnimation()
|
||||
.addElement(presentingElRoot.querySelector('.modal-shadow')!)
|
||||
.afterStyles({
|
||||
transform: toTransform,
|
||||
})
|
||||
.fromTo('opacity', '0', '0') // Shadow stays hidden
|
||||
.fromTo('transform', fromTransform, toTransform);
|
||||
|
||||
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
|
||||
}
|
||||
|
||||
return baseAnimation;
|
||||
};
|
@ -1,8 +1,8 @@
|
||||
import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Method, Prop, State, Watch, h, writeTask } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Listen, Method, Prop, State, Watch, h, writeTask } from '@stencil/core';
|
||||
import { findIonContent, printIonContentErrorMsg } from '@utils/content';
|
||||
import { CoreDelegate, attachComponent, detachComponent } from '@utils/framework-delegate';
|
||||
import { raf, inheritAttributes, hasLazyBuild } from '@utils/helpers';
|
||||
import { raf, inheritAttributes, hasLazyBuild, getElementRoot } from '@utils/helpers';
|
||||
import type { Attributes } from '@utils/helpers';
|
||||
import { createLockController } from '@utils/lock-controller';
|
||||
import { printIonWarning } from '@utils/logging';
|
||||
@ -37,11 +37,12 @@ import type { OverlayEventDetail } from '../../utils/overlays-interface';
|
||||
|
||||
import { iosEnterAnimation } from './animations/ios.enter';
|
||||
import { iosLeaveAnimation } from './animations/ios.leave';
|
||||
import { portraitToLandscapeTransition, landscapeToPortraitTransition } from './animations/ios.transition';
|
||||
import { mdEnterAnimation } from './animations/md.enter';
|
||||
import { mdLeaveAnimation } from './animations/md.leave';
|
||||
import type { MoveSheetToBreakpointOptions } from './gestures/sheet';
|
||||
import { createSheetGesture } from './gestures/sheet';
|
||||
import { createSwipeToCloseGesture } from './gestures/swipe-to-close';
|
||||
import { createSwipeToCloseGesture, SwipeToCloseDefaults } from './gestures/swipe-to-close';
|
||||
import type { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from './modal-interface';
|
||||
import { setCardStatusBarDark, setCardStatusBarDefault } from './utils';
|
||||
|
||||
@ -92,6 +93,11 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
// Whether or not modal is being dismissed via gesture
|
||||
private gestureAnimationDismissing = false;
|
||||
|
||||
// View transition properties for handling portrait/landscape switches
|
||||
private currentViewIsPortrait?: boolean;
|
||||
private viewTransitionAnimation?: Animation;
|
||||
private resizeTimeout?: any;
|
||||
|
||||
lastFocus?: HTMLElement;
|
||||
animation?: Animation;
|
||||
|
||||
@ -263,6 +269,19 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('resize', { target: 'window' })
|
||||
onWindowResize() {
|
||||
// Only handle resize for iOS card modals when no custom animations are provided
|
||||
if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(this.resizeTimeout);
|
||||
this.resizeTimeout = setTimeout(() => {
|
||||
this.handleViewTransition();
|
||||
}, 50); // Debounce to avoid excessive calls during active resizing
|
||||
}
|
||||
|
||||
/**
|
||||
* If `true`, the component passed into `ion-modal` will
|
||||
* automatically be mounted when the modal is created. The
|
||||
@ -389,6 +408,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
|
||||
disconnectedCallback() {
|
||||
this.triggerController.removeClickListener();
|
||||
this.cleanupViewTransitionListener();
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
@ -631,6 +651,9 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
this.initSwipeToClose();
|
||||
}
|
||||
|
||||
// Initialize view transition listener for iOS card modals
|
||||
this.initViewTransitionListener();
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
@ -830,6 +853,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
if (this.gesture) {
|
||||
this.gesture.destroy();
|
||||
}
|
||||
this.cleanupViewTransitionListener();
|
||||
}
|
||||
this.currentBreakpoint = undefined;
|
||||
this.animation = undefined;
|
||||
@ -993,6 +1017,134 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
}
|
||||
};
|
||||
|
||||
private initViewTransitionListener() {
|
||||
// Only enable for iOS card modals when no custom animations are provided
|
||||
if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set initial view state
|
||||
this.currentViewIsPortrait = window.innerWidth < 768;
|
||||
}
|
||||
|
||||
private handleViewTransition() {
|
||||
const isPortrait = window.innerWidth < 768;
|
||||
|
||||
// Only transition if view state actually changed
|
||||
if (this.currentViewIsPortrait === isPortrait) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel any ongoing transition animation
|
||||
if (this.viewTransitionAnimation) {
|
||||
this.viewTransitionAnimation.destroy();
|
||||
this.viewTransitionAnimation = undefined;
|
||||
}
|
||||
|
||||
const { presentingElement } = this;
|
||||
if (!presentingElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create transition animation
|
||||
let transitionAnimation: Animation;
|
||||
if (this.currentViewIsPortrait && !isPortrait) {
|
||||
// Portrait to landscape transition
|
||||
transitionAnimation = portraitToLandscapeTransition(this.el, {
|
||||
presentingEl: presentingElement,
|
||||
currentBreakpoint: this.currentBreakpoint,
|
||||
backdropBreakpoint: this.backdropBreakpoint,
|
||||
expandToScroll: this.expandToScroll,
|
||||
});
|
||||
} else {
|
||||
// Landscape to portrait transition
|
||||
transitionAnimation = landscapeToPortraitTransition(this.el, {
|
||||
presentingEl: presentingElement,
|
||||
currentBreakpoint: this.currentBreakpoint,
|
||||
backdropBreakpoint: this.backdropBreakpoint,
|
||||
expandToScroll: this.expandToScroll,
|
||||
});
|
||||
}
|
||||
|
||||
// Update state and play animation
|
||||
this.currentViewIsPortrait = isPortrait;
|
||||
this.viewTransitionAnimation = transitionAnimation;
|
||||
|
||||
transitionAnimation.play().then(() => {
|
||||
this.viewTransitionAnimation = undefined;
|
||||
|
||||
// After orientation transition, recreate the swipe-to-close gesture
|
||||
// with updated animation that reflects the new presenting element state
|
||||
this.reinitSwipeToClose();
|
||||
});
|
||||
}
|
||||
|
||||
private cleanupViewTransitionListener() {
|
||||
// Clear any pending resize timeout
|
||||
if (this.resizeTimeout) {
|
||||
clearTimeout(this.resizeTimeout);
|
||||
this.resizeTimeout = undefined;
|
||||
}
|
||||
|
||||
if (this.viewTransitionAnimation) {
|
||||
this.viewTransitionAnimation.destroy();
|
||||
this.viewTransitionAnimation = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private reinitSwipeToClose() {
|
||||
// Only reinitialize if we have a presenting element and are on iOS
|
||||
if (getIonMode(this) !== 'ios' || !this.presentingElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up existing gesture and animation
|
||||
if (this.gesture) {
|
||||
this.gesture.destroy();
|
||||
this.gesture = undefined;
|
||||
}
|
||||
|
||||
if (this.animation) {
|
||||
// Properly end the progress-based animation at initial state before destroying
|
||||
// to avoid leaving modal in intermediate swipe position
|
||||
this.animation.progressEnd(0, 0, 0);
|
||||
this.animation.destroy();
|
||||
this.animation = undefined;
|
||||
}
|
||||
|
||||
// Force the modal back to the correct position or it could end up
|
||||
// in a weird state after destroying the animation
|
||||
raf(() => {
|
||||
this.ensureCorrectModalPosition();
|
||||
this.initSwipeToClose();
|
||||
});
|
||||
}
|
||||
|
||||
private ensureCorrectModalPosition() {
|
||||
const { el, presentingElement } = this;
|
||||
const root = getElementRoot(el);
|
||||
|
||||
const wrapperEl = root.querySelector('.modal-wrapper') as HTMLElement | null;
|
||||
if (wrapperEl) {
|
||||
wrapperEl.style.transform = 'translateY(0vh)';
|
||||
wrapperEl.style.opacity = '1';
|
||||
}
|
||||
|
||||
if (presentingElement) {
|
||||
const isPortrait = window.innerWidth < 768;
|
||||
|
||||
if (isPortrait) {
|
||||
const transformOffset = !CSS.supports('width', 'max(0px, 1px)')
|
||||
? '30px'
|
||||
: 'max(30px, var(--ion-safe-area-top))';
|
||||
const scale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
||||
presentingElement.style.transform = `translateY(${transformOffset}) scale(${scale})`;
|
||||
} else {
|
||||
presentingElement.style.transform = 'translateY(0px) scale(1)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
handle,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { Page, TestInfo } from '@playwright/test';
|
||||
import type { E2EPageOptions, Mode, Direction, Theme, Palette } from '@utils/test/playwright';
|
||||
import type { Direction, E2EPageOptions, Mode, Palette, Theme } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* Overwrites the default Playwright page.setContent method.
|
||||
@ -36,6 +36,30 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
|
||||
|
||||
const baseUrl = process.env.PLAYWRIGHT_TEST_BASE_URL;
|
||||
|
||||
// The Ionic bundle is included locally by default unless the test
|
||||
// config passes in the importIonicFromCDN option. This is useful
|
||||
// when testing with the CDN version of Ionic.
|
||||
let ionicCSSImports = theme === 'ionic' ? `
|
||||
<link href="${baseUrl}/css/ionic/bundle.ionic.css" rel="stylesheet" />
|
||||
` : `
|
||||
<link href="${baseUrl}/css/ionic.bundle.css" rel="stylesheet" />
|
||||
`;
|
||||
let ionicJSImports = `
|
||||
<script type="module" src="${baseUrl}/dist/ionic/ionic.esm.js"></script>
|
||||
`;
|
||||
|
||||
if (options?.importIonicFromCDN) {
|
||||
ionicCSSImports = theme === 'ionic' ? `
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic/bundle.ionic.css" />
|
||||
` : `
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css" />
|
||||
`;
|
||||
ionicJSImports = `
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js"></script>
|
||||
<script nomodule src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js"></script>
|
||||
`;
|
||||
}
|
||||
|
||||
const output = `
|
||||
<!DOCTYPE html>
|
||||
<html dir="${direction}" lang="en">
|
||||
@ -43,15 +67,11 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
|
||||
<title>Ionic Playwright Test</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
|
||||
${
|
||||
theme === 'ionic'
|
||||
? `<link href="${baseUrl}/css/ionic/bundle.ionic.css" rel="stylesheet" />`
|
||||
: `<link href="${baseUrl}/css/ionic.bundle.css" rel="stylesheet" />`
|
||||
}
|
||||
${ionicCSSImports}
|
||||
<link href="${baseUrl}/scripts/testing/styles.css" rel="stylesheet" />
|
||||
${palette !== 'light' ? `<link href="${baseUrl}/css/palettes/${palette}.always.css" rel="stylesheet" />` : ''}
|
||||
<script src="${baseUrl}/scripts/testing/scripts.js"></script>
|
||||
<script type="module" src="${baseUrl}/dist/ionic/ionic.esm.js"></script>
|
||||
${ionicJSImports}
|
||||
<script>
|
||||
window.Ionic = {
|
||||
config: {
|
||||
|
@ -31,6 +31,12 @@ interface PageOptions {
|
||||
* - `'commit'` - consider operation to be finished when network response is received and the document started loading.
|
||||
*/
|
||||
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
|
||||
|
||||
/**
|
||||
* If true, the default Ionic imports will be included
|
||||
* via the CDN instead of the local bundle.
|
||||
*/
|
||||
importIonicFromCDN?: boolean;
|
||||
}
|
||||
|
||||
export interface E2EPage extends Page {
|
||||
|
@ -3,5 +3,5 @@
|
||||
"core",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "8.6.3"
|
||||
"version": "8.6.4"
|
||||
}
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
18
packages/angular-server/package-lock.json
generated
18
packages/angular-server/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3"
|
||||
"@ionic/core": "^8.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-eslint/eslint-plugin": "^16.0.0",
|
||||
@ -1031,9 +1031,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
@ -7305,9 +7305,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@ -62,6 +62,6 @@
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3"
|
||||
"@ionic/core": "^8.6.4"
|
||||
}
|
||||
}
|
||||
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
|
||||
|
18
packages/angular/package-lock.json
generated
18
packages/angular/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3",
|
||||
"@ionic/core": "^8.6.4",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
@ -1398,9 +1398,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
@ -9936,9 +9936,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@ -47,7 +47,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3",
|
||||
"@ionic/core": "^8.6.4",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
4
packages/docs/package-lock.json
generated
4
packages/docs/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/docs",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"types": "core.d.ts",
|
||||
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
34
packages/react-router/package-lock.json
generated
34
packages/react-router/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react-router",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/react": "^8.6.3",
|
||||
"@ionic/react": "^8.6.4",
|
||||
"tslib": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -238,9 +238,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
@ -415,12 +415,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.6.3.tgz",
|
||||
"integrity": "sha512-wBFn6cOKuRKJfUNBz1SyexLkqs+QdaSImEJJ5wepaIF5A94rKlG0JQGCCZjT0KaLbJ+UaQuCgRRQWUrT0XJKDQ==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.6.4.tgz",
|
||||
"integrity": "sha512-X2jIi4TN/u9hlsy/BrubyJbIZ4Pn8cnbBFu/emQ1y7VH0rpVVWPgeHb8cKMJPNbKzszuvO+f5huGliNIYFIQ8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "8.6.3",
|
||||
"@ionic/core": "8.6.4",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@ -4175,9 +4175,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
@ -4281,11 +4281,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/react": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.6.3.tgz",
|
||||
"integrity": "sha512-wBFn6cOKuRKJfUNBz1SyexLkqs+QdaSImEJJ5wepaIF5A94rKlG0JQGCCZjT0KaLbJ+UaQuCgRRQWUrT0XJKDQ==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.6.4.tgz",
|
||||
"integrity": "sha512-X2jIi4TN/u9hlsy/BrubyJbIZ4Pn8cnbBFu/emQ1y7VH0rpVVWPgeHb8cKMJPNbKzszuvO+f5huGliNIYFIQ8A==",
|
||||
"requires": {
|
||||
"@ionic/core": "8.6.3",
|
||||
"@ionic/core": "8.6.4",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "React Router wrapper for @ionic/react",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@ -36,7 +36,7 @@
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/react": "^8.6.3",
|
||||
"@ionic/react": "^8.6.4",
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
18
packages/react/package-lock.json
generated
18
packages/react/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3",
|
||||
"@ionic/core": "^8.6.4",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@ -736,9 +736,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
@ -12431,9 +12431,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "React specific wrapper for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@ -39,7 +39,7 @@
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3",
|
||||
"@ionic/core": "^8.6.4",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
34
packages/vue-router/package-lock.json
generated
34
packages/vue-router/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^8.6.3"
|
||||
"@ionic/vue": "^8.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
@ -673,9 +673,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
@ -865,12 +865,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/vue": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.6.3.tgz",
|
||||
"integrity": "sha512-vQb0lMs3TKbcEZQz1SF7E4TzZf0wRf3elJaIFd0PRa4+Shcn5zpliid8uCJTlPY5k943axIrPNxKaQPJFQXdrw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.6.4.tgz",
|
||||
"integrity": "sha512-vhFxCUk2hwPbJS1uTcZkVFB+9eFfzeis5TyL1mDmlULFhbGI/YTLTcWcXWSdG/myg4yPeb8brObWpMq36StJVw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "8.6.3",
|
||||
"@ionic/core": "8.6.4",
|
||||
"@stencil/vue-output-target": "0.10.7",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
@ -8041,9 +8041,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
@ -8156,11 +8156,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/vue": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.6.3.tgz",
|
||||
"integrity": "sha512-vQb0lMs3TKbcEZQz1SF7E4TzZf0wRf3elJaIFd0PRa4+Shcn5zpliid8uCJTlPY5k943axIrPNxKaQPJFQXdrw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.6.4.tgz",
|
||||
"integrity": "sha512-vhFxCUk2hwPbJS1uTcZkVFB+9eFfzeis5TyL1mDmlULFhbGI/YTLTcWcXWSdG/myg4yPeb8brObWpMq36StJVw==",
|
||||
"requires": {
|
||||
"@ionic/core": "8.6.3",
|
||||
"@ionic/core": "8.6.4",
|
||||
"@stencil/vue-output-target": "0.10.7",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "Vue Router integration for @ionic/vue",
|
||||
"scripts": {
|
||||
"test.spec": "jest",
|
||||
@ -44,7 +44,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/ionic-team/ionic-framework#readme",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^8.6.3"
|
||||
"@ionic/vue": "^8.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
|
@ -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.4](https://github.com/ionic-team/ionic-framework/compare/v8.6.3...v8.6.4) (2025-07-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.3](https://github.com/ionic-team/ionic-framework/compare/v8.6.2...v8.6.3) (2025-07-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
18
packages/vue/package-lock.json
generated
18
packages/vue/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3",
|
||||
"@ionic/core": "^8.6.4",
|
||||
"@stencil/vue-output-target": "0.10.7",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
@ -222,9 +222,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
@ -4167,9 +4167,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.3.tgz",
|
||||
"integrity": "sha512-N/mkw+sPecLEoO1lrnKDS0uZgl6PWSyFprCkkqoK1nHlfBkgFiHm5M9rvWlnGaFC/5xrhNGHdUtYHDFM+F8gRw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.4.tgz",
|
||||
"integrity": "sha512-6kOx0yQAkXkMvhe6fQPA034LgmCh4aL0nJ+GwzNMwLYAe2fVq6mRdM37jNldGiGIZ0Q9Te2sHTFTM/IGItuIyQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "8.6.3",
|
||||
"version": "8.6.4",
|
||||
"description": "Vue specific wrapper for @ionic/core",
|
||||
"scripts": {
|
||||
"eslint": "eslint src",
|
||||
@ -67,7 +67,7 @@
|
||||
"vue-router": "^4.0.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.3",
|
||||
"@ionic/core": "^8.6.4",
|
||||
"@stencil/vue-output-target": "0.10.7",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
|
Reference in New Issue
Block a user