Compare commits
16 Commits
sp/refacto
...
v7.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cb37430d3 | ||
|
|
e9fa30002b | ||
|
|
07dee74714 | ||
|
|
aa326a6eda | ||
|
|
1cf1eca002 | ||
|
|
eb19c289d6 | ||
|
|
a0e6ac6013 | ||
|
|
da55ab949e | ||
|
|
a0b3ef02af | ||
|
|
9500769f11 | ||
|
|
5992c619ad | ||
|
|
01857dd315 | ||
|
|
dbe6f390ef | ||
|
|
0c117cfe7f | ||
|
|
f14c440d63 | ||
|
|
bd1910ba69 |
33
CHANGELOG.md
@@ -3,6 +3,39 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** hidden button is added when form is set async ([#27955](https://github.com/ionic-team/ionic-framework/issues/27955)) ([e9fa300](https://github.com/ionic-team/ionic-framework/commit/e9fa30002bd5dec4f2f56a15c84eec1b3e794942)), closes [#27952](https://github.com/ionic-team/ionic-framework/issues/27952)
|
||||
* **datetime:** changing months work if partially visible ([#27917](https://github.com/ionic-team/ionic-framework/issues/27917)) ([eb19c28](https://github.com/ionic-team/ionic-framework/commit/eb19c289d6581639f6df7aff002bebdf2b27d31c)), closes [#27913](https://github.com/ionic-team/ionic-framework/issues/27913)
|
||||
* **item-sliding:** account for options added before watcher ([#27915](https://github.com/ionic-team/ionic-framework/issues/27915)) ([a0b3ef0](https://github.com/ionic-team/ionic-framework/commit/a0b3ef02af718e232246515bb873ad8c090fa55d)), closes [#27910](https://github.com/ionic-team/ionic-framework/issues/27910)
|
||||
* **many:** overlays present if isOpen is true on load ([#27933](https://github.com/ionic-team/ionic-framework/issues/27933)) ([a0e6ac6](https://github.com/ionic-team/ionic-framework/commit/a0e6ac6013552c5e3acdde33575d4aaf4d4c0bda)), closes [#27928](https://github.com/ionic-team/ionic-framework/issues/27928)
|
||||
* **modal:** setCurrentBreakpoint respects animated prop ([#27924](https://github.com/ionic-team/ionic-framework/issues/27924)) ([da55ab9](https://github.com/ionic-team/ionic-framework/commit/da55ab949ef1894738da5a6241176089b7a2b6e3)), closes [#27923](https://github.com/ionic-team/ionic-framework/issues/27923)
|
||||
* **nav:** improve reliability of swipe back gesture when quickly swiping back ([#27904](https://github.com/ionic-team/ionic-framework/issues/27904)) ([9500769](https://github.com/ionic-team/ionic-framework/commit/9500769f114d180613f0340b1a328b5e631b7188)), closes [#27893](https://github.com/ionic-team/ionic-framework/issues/27893)
|
||||
* **tab-button:** update event type interface on React ([#27950](https://github.com/ionic-team/ionic-framework/issues/27950)) ([1cf1eca](https://github.com/ionic-team/ionic-framework/commit/1cf1eca00239f3e98854466116e42f9a2e7b4590)), closes [#27949](https://github.com/ionic-team/ionic-framework/issues/27949)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **datetime-button:** render correct text when passing partial date values ([#27816](https://github.com/ionic-team/ionic-framework/issues/27816)) ([bd1910b](https://github.com/ionic-team/ionic-framework/commit/bd1910ba69348877ad5f99d9db2b59d06693b91e)), closes [#27797](https://github.com/ionic-team/ionic-framework/issues/27797)
|
||||
* **input, textarea:** input does not block floating label ([#27870](https://github.com/ionic-team/ionic-framework/issues/27870)) ([f14c440](https://github.com/ionic-team/ionic-framework/commit/f14c440d6321ef9f168b272338e5cd21cab384ef)), closes [#27812](https://github.com/ionic-team/ionic-framework/issues/27812)
|
||||
* **item-options:** use correct safe area padding ([#27853](https://github.com/ionic-team/ionic-framework/issues/27853)) ([0b8f1bc](https://github.com/ionic-team/ionic-framework/commit/0b8f1bc7dd4170a2a8c9ed3aede173dd489b25ea))
|
||||
* **radio:** radios can be focused and are announced with group ([#27817](https://github.com/ionic-team/ionic-framework/issues/27817)) ([ba2f49b](https://github.com/ionic-team/ionic-framework/commit/ba2f49b8a460520d20ac198db800ea2d9e5b015f)), closes [#27438](https://github.com/ionic-team/ionic-framework/issues/27438)
|
||||
* **react, vue:** custom animations are used when going back ([#27895](https://github.com/ionic-team/ionic-framework/issues/27895)) ([824033f](https://github.com/ionic-team/ionic-framework/commit/824033f1d4b4a3e5d4c6a978a39e5bb1f33b5bb4)), closes [#27873](https://github.com/ionic-team/ionic-framework/issues/27873)
|
||||
* **select:** popover uses modern form syntax ([#27818](https://github.com/ionic-team/ionic-framework/issues/27818)) ([0c117cf](https://github.com/ionic-team/ionic-framework/commit/0c117cfe7f383b7c7837d27de5a6eee12ddd6c2f)), closes [#27071](https://github.com/ionic-team/ionic-framework/issues/27071) [#27786](https://github.com/ionic-team/ionic-framework/issues/27786)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,37 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** hidden button is added when form is set async ([#27955](https://github.com/ionic-team/ionic-framework/issues/27955)) ([e9fa300](https://github.com/ionic-team/ionic-framework/commit/e9fa30002bd5dec4f2f56a15c84eec1b3e794942)), closes [#27952](https://github.com/ionic-team/ionic-framework/issues/27952)
|
||||
* **datetime:** changing months work if partially visible ([#27917](https://github.com/ionic-team/ionic-framework/issues/27917)) ([eb19c28](https://github.com/ionic-team/ionic-framework/commit/eb19c289d6581639f6df7aff002bebdf2b27d31c)), closes [#27913](https://github.com/ionic-team/ionic-framework/issues/27913)
|
||||
* **item-sliding:** account for options added before watcher ([#27915](https://github.com/ionic-team/ionic-framework/issues/27915)) ([a0b3ef0](https://github.com/ionic-team/ionic-framework/commit/a0b3ef02af718e232246515bb873ad8c090fa55d)), closes [#27910](https://github.com/ionic-team/ionic-framework/issues/27910)
|
||||
* **many:** overlays present if isOpen is true on load ([#27933](https://github.com/ionic-team/ionic-framework/issues/27933)) ([a0e6ac6](https://github.com/ionic-team/ionic-framework/commit/a0e6ac6013552c5e3acdde33575d4aaf4d4c0bda)), closes [#27928](https://github.com/ionic-team/ionic-framework/issues/27928)
|
||||
* **modal:** setCurrentBreakpoint respects animated prop ([#27924](https://github.com/ionic-team/ionic-framework/issues/27924)) ([da55ab9](https://github.com/ionic-team/ionic-framework/commit/da55ab949ef1894738da5a6241176089b7a2b6e3)), closes [#27923](https://github.com/ionic-team/ionic-framework/issues/27923)
|
||||
* **nav:** improve reliability of swipe back gesture when quickly swiping back ([#27904](https://github.com/ionic-team/ionic-framework/issues/27904)) ([9500769](https://github.com/ionic-team/ionic-framework/commit/9500769f114d180613f0340b1a328b5e631b7188)), closes [#27893](https://github.com/ionic-team/ionic-framework/issues/27893)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **datetime-button:** render correct text when passing partial date values ([#27816](https://github.com/ionic-team/ionic-framework/issues/27816)) ([bd1910b](https://github.com/ionic-team/ionic-framework/commit/bd1910ba69348877ad5f99d9db2b59d06693b91e)), closes [#27797](https://github.com/ionic-team/ionic-framework/issues/27797)
|
||||
* **input, textarea:** input does not block floating label ([#27870](https://github.com/ionic-team/ionic-framework/issues/27870)) ([f14c440](https://github.com/ionic-team/ionic-framework/commit/f14c440d6321ef9f168b272338e5cd21cab384ef)), closes [#27812](https://github.com/ionic-team/ionic-framework/issues/27812)
|
||||
* **item-options:** use correct safe area padding ([#27853](https://github.com/ionic-team/ionic-framework/issues/27853)) ([0b8f1bc](https://github.com/ionic-team/ionic-framework/commit/0b8f1bc7dd4170a2a8c9ed3aede173dd489b25ea))
|
||||
* **radio:** radios can be focused and are announced with group ([#27817](https://github.com/ionic-team/ionic-framework/issues/27817)) ([ba2f49b](https://github.com/ionic-team/ionic-framework/commit/ba2f49b8a460520d20ac198db800ea2d9e5b015f)), closes [#27438](https://github.com/ionic-team/ionic-framework/issues/27438)
|
||||
* **select:** popover uses modern form syntax ([#27818](https://github.com/ionic-team/ionic-framework/issues/27818)) ([0c117cf](https://github.com/ionic-team/ionic-framework/commit/0c117cfe7f383b7c7837d27de5a6eee12ddd6c2f)), closes [#27071](https://github.com/ionic-team/ionic-framework/issues/27071) [#27786](https://github.com/ionic-team/ionic-framework/issues/27786)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
|
||||
|
||||
4
core/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Watch, Component, Element, Event, Host, Method, Prop, h, readTask } from '@stencil/core';
|
||||
import type { Gesture } from '@utils/gesture';
|
||||
import { createButtonActiveGesture } from '@utils/gesture/button-active';
|
||||
import { raf } from '@utils/helpers';
|
||||
import {
|
||||
BACKDROP,
|
||||
createDelegateController,
|
||||
@@ -318,25 +319,32 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
||||
|
||||
componentDidLoad() {
|
||||
/**
|
||||
* Do not create gesture if:
|
||||
* 1. A gesture already exists
|
||||
* 2. App is running in MD mode
|
||||
* 3. A wrapper ref does not exist
|
||||
* Only create gesture if:
|
||||
* 1. A gesture does not already exist
|
||||
* 2. App is running in iOS mode
|
||||
* 3. A wrapper ref exists
|
||||
* 4. A group ref exists
|
||||
*/
|
||||
const { groupEl, wrapperEl } = this;
|
||||
if (this.gesture || getIonMode(this) === 'md' || !wrapperEl || !groupEl) {
|
||||
return;
|
||||
if (!this.gesture && getIonMode(this) === 'ios' && wrapperEl && groupEl) {
|
||||
readTask(() => {
|
||||
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
|
||||
if (!isScrollable) {
|
||||
this.gesture = createButtonActiveGesture(wrapperEl, (refEl: HTMLElement) =>
|
||||
refEl.classList.contains('action-sheet-button')
|
||||
);
|
||||
this.gesture.enable(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readTask(() => {
|
||||
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
|
||||
if (!isScrollable) {
|
||||
this.gesture = createButtonActiveGesture(wrapperEl, (refEl: HTMLElement) =>
|
||||
refEl.classList.contains('action-sheet-button')
|
||||
);
|
||||
this.gesture.enable(true);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* If action sheet was rendered with isOpen="true"
|
||||
* then we should open action sheet immediately.
|
||||
*/
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -30,5 +30,10 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ config, title }) =>
|
||||
|
||||
await expect(actionSheet).toBeHidden();
|
||||
});
|
||||
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-action-sheet is-open="true"></ion-action-sheet>', config);
|
||||
await expect(page.locator('ion-action-sheet')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component, Element, Event, Host, Listen, Method, Prop, Watch, forceUpda
|
||||
import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config';
|
||||
import type { Gesture } from '@utils/gesture';
|
||||
import { createButtonActiveGesture } from '@utils/gesture/button-active';
|
||||
import { raf } from '@utils/helpers';
|
||||
import {
|
||||
createDelegateController,
|
||||
createTriggerController,
|
||||
@@ -346,19 +347,25 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
|
||||
componentDidLoad() {
|
||||
/**
|
||||
* Do not create gesture if:
|
||||
* 1. A gesture already exists
|
||||
* 2. App is running in MD mode
|
||||
* 3. A wrapper ref does not exist
|
||||
* Only create gesture if:
|
||||
* 1. A gesture does not already exist
|
||||
* 2. App is running in iOS mode
|
||||
* 3. A wrapper ref exists
|
||||
*/
|
||||
if (this.gesture || getIonMode(this) === 'md' || !this.wrapperEl) {
|
||||
return;
|
||||
if (!this.gesture && getIonMode(this) === 'ios' && this.wrapperEl) {
|
||||
this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl: HTMLElement) =>
|
||||
refEl.classList.contains('alert-button')
|
||||
);
|
||||
this.gesture.enable(true);
|
||||
}
|
||||
|
||||
this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl: HTMLElement) =>
|
||||
refEl.classList.contains('alert-button')
|
||||
);
|
||||
this.gesture.enable(true);
|
||||
/**
|
||||
* If alert was rendered with isOpen="true"
|
||||
* then we should open alert immediately.
|
||||
*/
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,5 +29,10 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ config, title }) =>
|
||||
await ionAlertDidDismiss.next();
|
||||
await expect(alert).toBeHidden();
|
||||
});
|
||||
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-alert is-open="true"></ion-alert>', config);
|
||||
await expect(page.locator('ion-alert')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,19 +153,27 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
*/
|
||||
@Event() ionBlur!: EventEmitter<void>;
|
||||
|
||||
connectedCallback(): void {
|
||||
// Allow form to be submitted through `ion-button`
|
||||
if (this.type !== 'button' && hasShadowDom(this.el)) {
|
||||
this.formEl = this.findForm();
|
||||
if (this.formEl) {
|
||||
// Create a hidden native button inside of the form
|
||||
this.formButtonEl = document.createElement('button');
|
||||
this.formButtonEl.type = this.type;
|
||||
this.formButtonEl.style.display = 'none';
|
||||
// Only submit if the button is not disabled.
|
||||
this.formButtonEl.disabled = this.disabled;
|
||||
this.formEl.appendChild(this.formButtonEl);
|
||||
private renderHiddenButton() {
|
||||
const formEl = (this.formEl = this.findForm());
|
||||
if (formEl) {
|
||||
const { formButtonEl } = this;
|
||||
|
||||
/**
|
||||
* If the form already has a rendered form button
|
||||
* then do not append a new one again.
|
||||
*/
|
||||
if (formButtonEl !== null && formEl.contains(formButtonEl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a hidden native button inside of the form
|
||||
const newFormButtonEl = (this.formButtonEl = document.createElement('button'));
|
||||
newFormButtonEl.type = this.type;
|
||||
newFormButtonEl.style.display = 'none';
|
||||
// Only submit if the button is not disabled.
|
||||
newFormButtonEl.disabled = this.disabled;
|
||||
|
||||
formEl.appendChild(newFormButtonEl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,6 +322,11 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
if (fill == null) {
|
||||
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
|
||||
}
|
||||
|
||||
{
|
||||
type !== 'button' && this.renderHiddenButton();
|
||||
}
|
||||
|
||||
return (
|
||||
<Host
|
||||
onClick={this.handleClick}
|
||||
|
||||
@@ -130,6 +130,29 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
|
||||
expect(submitEvent).not.toHaveReceivedEvent();
|
||||
});
|
||||
|
||||
test('should submit the form by id when form is set async', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/27952',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<form id="myForm"></form>
|
||||
<ion-button type="submit">Submit</ion-button>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const submitEvent = await page.spyOnEvent('submit');
|
||||
const button = page.locator('ion-button');
|
||||
|
||||
await button.evaluate((el: HTMLIonButtonElement) => (el.form = 'myForm'));
|
||||
|
||||
await page.click('ion-button');
|
||||
|
||||
expect(submitEvent).toHaveReceivedEvent();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe(title('should throw a warning if the form cannot be found'), () => {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { newSpecPage } from '@stencil/core/testing';
|
||||
import { Button } from '../../button';
|
||||
|
||||
describe('Button: Hidden Form Button', () => {
|
||||
it('should not add multiple buttons to the form', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Button],
|
||||
html: `
|
||||
<form id="my-form"></form>
|
||||
<ion-button form="my-form" type="submit">Submit</ion-button>
|
||||
`,
|
||||
});
|
||||
|
||||
const getButtons = () => {
|
||||
return page.body.querySelectorAll('form button');
|
||||
};
|
||||
|
||||
const form = page.body.querySelectorAll('form');
|
||||
const button = page.body.querySelector('ion-button');
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
expect(getButtons().length).toEqual(1);
|
||||
|
||||
// Re-render the component
|
||||
button.color = 'danger';
|
||||
await page.waitForChanges();
|
||||
|
||||
expect(getButtons().length).toEqual(1);
|
||||
});
|
||||
});
|
||||
@@ -122,6 +122,42 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await expect(dateTarget).toContainText('May 10, 2023');
|
||||
});
|
||||
test('should set only month and year when only passing month and year', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/27797',
|
||||
});
|
||||
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime-button locale="en-US" datetime="datetime"></ion-datetime-button>
|
||||
<ion-datetime id="datetime" value="2022-01" presentation="month-year"></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
await expect(page.locator('#date-button')).toContainText('January 2022');
|
||||
await expect(page.locator('#time-button')).toBeHidden();
|
||||
});
|
||||
test('should set only year when passing only year', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/27797',
|
||||
});
|
||||
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime-button locale="en-US" datetime="datetime"></ion-datetime-button>
|
||||
<ion-datetime id="datetime" value="2022" presentation="year"></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
await expect(page.locator('#date-button')).toContainText('2022');
|
||||
await expect(page.locator('#time-button')).toBeHidden();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe(title('datetime-button: locale'), () => {
|
||||
|
||||
@@ -138,7 +138,6 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
@Element() el!: HTMLIonDatetimeElement;
|
||||
|
||||
@State() isPresented = false;
|
||||
@State() isTimePopoverOpen = false;
|
||||
|
||||
/**
|
||||
@@ -883,21 +882,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
const getChangedMonth = (parts: DatetimeParts): DatetimeParts | undefined => {
|
||||
const box = calendarBodyRef.getBoundingClientRect();
|
||||
const root = this.el!.shadowRoot!;
|
||||
|
||||
/**
|
||||
* Get the element that is in the center of the calendar body.
|
||||
* This will be an element inside of the active month.
|
||||
* If the current scroll position is all the way to the left
|
||||
* then we have scrolled to the previous month.
|
||||
* Otherwise, assume that we have scrolled to the next
|
||||
* month. We have a tolerance of 2px to account for
|
||||
* sub pixel rendering.
|
||||
*
|
||||
* Check below the next line ensures that we did not
|
||||
* swipe and abort (i.e. we swiped but we are still on the current month).
|
||||
*/
|
||||
const elementAtCenter = root.elementFromPoint(box.x + box.width / 2, box.y + box.height / 2);
|
||||
/**
|
||||
* If there is no element then the
|
||||
* component may be re-rendering on a slow device.
|
||||
*/
|
||||
if (!elementAtCenter) return;
|
||||
|
||||
const month = elementAtCenter.closest('.calendar-month');
|
||||
if (!month) return;
|
||||
const month = calendarBodyRef.scrollLeft <= 2 ? startMonth : endMonth;
|
||||
|
||||
/**
|
||||
* The edge of the month must be lined up with
|
||||
@@ -2364,19 +2360,7 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
value,
|
||||
disabled,
|
||||
el,
|
||||
color,
|
||||
isPresented,
|
||||
readonly,
|
||||
showMonthAndYear,
|
||||
preferWheel,
|
||||
presentation,
|
||||
size,
|
||||
} = this;
|
||||
const { name, value, disabled, el, color, readonly, showMonthAndYear, preferWheel, presentation, size } = this;
|
||||
const mode = getIonMode(this);
|
||||
const isMonthAndYearPresentation =
|
||||
presentation === 'year' || presentation === 'month' || presentation === 'month-year';
|
||||
@@ -2396,7 +2380,6 @@ export class Datetime implements ComponentInterface {
|
||||
class={{
|
||||
...createColorClasses(color, {
|
||||
[mode]: true,
|
||||
['datetime-presented']: isPresented,
|
||||
['datetime-readonly']: readonly,
|
||||
['datetime-disabled']: disabled,
|
||||
'show-month-and-year': shouldShowMonthAndYear,
|
||||
|
||||
@@ -301,21 +301,20 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
<ion-datetime
|
||||
min="2022-01-15"
|
||||
value="2022-02-01"
|
||||
presentation="date"
|
||||
presentation="month-year"
|
||||
></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
await monthYearToggle.click();
|
||||
await page.waitForChanges();
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
await monthColumnItems.nth(0).click(); // switch to January
|
||||
await page.waitForChanges();
|
||||
await ionChange.next();
|
||||
|
||||
await expect(datetime).toHaveJSProperty('value', '2022-01-15T00:00:00');
|
||||
});
|
||||
|
||||
@@ -34,13 +34,14 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const activeDayButton = page.locator('.calendar-day-active');
|
||||
const monthYearButton = page.locator('.calendar-month-year');
|
||||
const monthColumn = page.locator('.month-column');
|
||||
const yearColumn = page.locator('.year-column');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
await datetime.evaluate((el: HTMLIonDatetimeElement) => (el.value = '2021-10-05'));
|
||||
|
||||
@@ -49,11 +50,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
await page.waitForChanges();
|
||||
|
||||
// Select October 2021
|
||||
// The year will automatically switch to 2021 when selecting 10
|
||||
await monthColumn.locator('.picker-item[data-value="10"]').click();
|
||||
await page.waitForChanges();
|
||||
|
||||
await yearColumn.locator('.picker-item[data-value="2021"]').click();
|
||||
await page.waitForChanges();
|
||||
await ionChange.next();
|
||||
|
||||
// Close month/year picker
|
||||
await monthYearButton.click();
|
||||
|
||||
@@ -113,7 +113,7 @@ export const generateDayAriaLabel = (locale: string, today: boolean, refParts: D
|
||||
/**
|
||||
* MM/DD/YYYY will return midnight in the user's timezone.
|
||||
*/
|
||||
const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
|
||||
const date = getNormalizedDate(refParts);
|
||||
|
||||
const labelString = new Intl.DateTimeFormat(locale, {
|
||||
weekday: 'long',
|
||||
@@ -134,7 +134,7 @@ export const generateDayAriaLabel = (locale: string, today: boolean, refParts: D
|
||||
* Used for the header in MD mode.
|
||||
*/
|
||||
export const getMonthAndDay = (locale: string, refParts: DatetimeParts) => {
|
||||
const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
|
||||
const date = getNormalizedDate(refParts);
|
||||
return new Intl.DateTimeFormat(locale, { weekday: 'short', month: 'short', day: 'numeric', timeZone: 'UTC' }).format(
|
||||
date
|
||||
);
|
||||
@@ -147,7 +147,7 @@ export const getMonthAndDay = (locale: string, refParts: DatetimeParts) => {
|
||||
* Example: May 2021
|
||||
*/
|
||||
export const getMonthAndYear = (locale: string, refParts: DatetimeParts) => {
|
||||
const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
|
||||
const date = getNormalizedDate(refParts);
|
||||
return new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric', timeZone: 'UTC' }).format(date);
|
||||
};
|
||||
|
||||
@@ -183,11 +183,25 @@ export const getYear = (locale: string, refParts: DatetimeParts) => {
|
||||
return getLocalizedDateTime(locale, refParts, { year: 'numeric' });
|
||||
};
|
||||
|
||||
const getNormalizedDate = (refParts: DatetimeParts) => {
|
||||
/**
|
||||
* Given reference parts, return a JS Date object
|
||||
* with a normalized time.
|
||||
*/
|
||||
export const getNormalizedDate = (refParts: DatetimeParts) => {
|
||||
const timeString =
|
||||
refParts.hour !== undefined && refParts.minute !== undefined ? ` ${refParts.hour}:${refParts.minute}` : '';
|
||||
|
||||
return new Date(`${refParts.month}/${refParts.day}/${refParts.year}${timeString} GMT+0000`);
|
||||
/**
|
||||
* We use / notation here for the date
|
||||
* so we do not need to do extra work and pad values with zeroes.
|
||||
* Values such as YYYY-MM are still valid, so
|
||||
* we add fallback values so we still get
|
||||
* a valid date otherwise we will pass in a string
|
||||
* like "//2023". Some browsers, such as Chrome, will
|
||||
* account for this and still return a valid date. However,
|
||||
* this is not a consistent behavior across all browsers.
|
||||
*/
|
||||
return new Date(`${refParts.month ?? 1}/${refParts.day ?? 1}/${refParts.year ?? 2023}${timeString} GMT+0000`);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -82,8 +82,6 @@
|
||||
:host(.input-fill-outline) .label-text-wrapper,
|
||||
:host(.input-fill-outline) .label-text-wrapper {
|
||||
position: relative;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -581,6 +581,13 @@
|
||||
@include transform-origin(start, top);
|
||||
|
||||
max-width: 100%;
|
||||
|
||||
/**
|
||||
* The 2 ensures the label
|
||||
* remains on top of any browser
|
||||
* autofill background too.
|
||||
*/
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,9 +186,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
||||
expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-slot-truncate`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('input: async label'), () => {
|
||||
test('input should re-render when label slot is added async', async ({ page }) => {
|
||||
await page.setContent(
|
||||
@@ -213,4 +210,27 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
||||
expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-async-label`));
|
||||
});
|
||||
});
|
||||
test.describe(title('input: floating/stacked label layering'), () => {
|
||||
test('label should not be covered by text field', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/27812',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
.custom-input .native-wrapper {
|
||||
background: pink;
|
||||
}
|
||||
</style>
|
||||
<ion-input class="custom-input" label="My Label" label-placement="stacked"></ion-input>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const input = page.locator('ion-input');
|
||||
|
||||
expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-layering`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
@@ -76,12 +76,19 @@ export class ItemSliding implements ComponentInterface {
|
||||
this.item = el.querySelector('ion-item');
|
||||
this.contentEl = findClosestIonContent(el);
|
||||
|
||||
await this.updateOptions();
|
||||
|
||||
/**
|
||||
* The MutationObserver needs to be added before we
|
||||
* call updateOptions below otherwise we may miss
|
||||
* ion-item-option elements that are added to the DOM
|
||||
* while updateOptions is running and before the MutationObserver
|
||||
* has been initialized.
|
||||
*/
|
||||
this.mutationObserver = watchForOptions<HTMLIonItemOptionElement>(el, 'ion-item-option', async () => {
|
||||
await this.updateOptions();
|
||||
});
|
||||
|
||||
await this.updateOptions();
|
||||
|
||||
this.gesture = (await import('../../utils/gesture')).createGesture({
|
||||
el,
|
||||
gestureName: 'item-swipe',
|
||||
|
||||
@@ -23,5 +23,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
await ionLoadingDidDismiss.next();
|
||||
await expect(loading).toBeHidden();
|
||||
});
|
||||
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-loading is-open="true"></ion-loading>', config);
|
||||
await expect(page.locator('ion-loading')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,6 +31,12 @@ export interface MoveSheetToBreakpointOptions {
|
||||
* `true` if the sheet can be transitioned and dismissed off the view.
|
||||
*/
|
||||
canDismiss?: boolean;
|
||||
|
||||
/**
|
||||
* If `true`, the sheet will animate to the breakpoint.
|
||||
* If `false`, the sheet will jump directly to the breakpoint.
|
||||
*/
|
||||
animated: boolean;
|
||||
}
|
||||
|
||||
export const createSheetGesture = (
|
||||
@@ -246,11 +252,17 @@ export const createSheetGesture = (
|
||||
breakpoint: closest,
|
||||
breakpointOffset: offset,
|
||||
canDismiss: canDismissBlocksGesture,
|
||||
|
||||
/**
|
||||
* The swipe is user-driven, so we should
|
||||
* always animate when the gesture ends.
|
||||
*/
|
||||
animated: true,
|
||||
});
|
||||
};
|
||||
|
||||
const moveSheetToBreakpoint = (options: MoveSheetToBreakpointOptions) => {
|
||||
const { breakpoint, canDismiss, breakpointOffset } = options;
|
||||
const { breakpoint, canDismiss, breakpointOffset, animated } = options;
|
||||
/**
|
||||
* canDismiss should only prevent snapping
|
||||
* when users are trying to dismiss. If canDismiss
|
||||
@@ -360,7 +372,7 @@ export const createSheetGesture = (
|
||||
},
|
||||
{ oneTimeCallback: true }
|
||||
)
|
||||
.progressEnd(1, 0, 500);
|
||||
.progressEnd(1, 0, animated ? 500 : 0);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -761,7 +761,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
const { currentBreakpoint, moveSheetToBreakpoint, canDismiss, breakpoints } = this;
|
||||
const { currentBreakpoint, moveSheetToBreakpoint, canDismiss, breakpoints, animated } = this;
|
||||
|
||||
if (currentBreakpoint === breakpoint) {
|
||||
return;
|
||||
@@ -772,6 +772,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
breakpoint,
|
||||
breakpointOffset: 1 - currentBreakpoint!,
|
||||
canDismiss: canDismiss !== undefined && canDismiss !== true && breakpoints![0] === 0,
|
||||
animated,
|
||||
});
|
||||
await this.sheetTransition;
|
||||
this.sheetTransition = undefined;
|
||||
|
||||
@@ -20,5 +20,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
await ionModalDidDismiss.next();
|
||||
await expect(modal).toBeHidden();
|
||||
});
|
||||
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-modal is-open="true"></ion-modal>', config);
|
||||
await expect(page.locator('ion-modal')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ import { VIEW_STATE_ATTACHED, VIEW_STATE_DESTROYED, VIEW_STATE_NEW, convertToVie
|
||||
export class Nav implements NavOutlet {
|
||||
private transInstr: TransitionInstruction[] = [];
|
||||
private sbAni?: Animation;
|
||||
private animationEnabled = true;
|
||||
private gestureOrAnimationInProgress = false;
|
||||
private useRouter = false;
|
||||
private isTransitioning = false;
|
||||
private destroyed = false;
|
||||
@@ -869,7 +869,36 @@ export class Nav implements NavOutlet {
|
||||
// or if it is a portal (modal, actionsheet, etc.)
|
||||
const opts = ti.opts!;
|
||||
|
||||
const progressCallback = opts.progressAnimation ? (ani: Animation | undefined) => (this.sbAni = ani) : undefined;
|
||||
const progressCallback = opts.progressAnimation
|
||||
? (ani: Animation | undefined) => {
|
||||
/**
|
||||
* Because this progress callback is called asynchronously
|
||||
* it is possible for the gesture to start and end before
|
||||
* the animation is ever set. In that scenario, we should
|
||||
* immediately call progressEnd so that the transition promise
|
||||
* resolves and the gesture does not get locked up.
|
||||
*/
|
||||
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
|
||||
this.gestureOrAnimationInProgress = true;
|
||||
ani.onFinish(
|
||||
() => {
|
||||
this.gestureOrAnimationInProgress = false;
|
||||
},
|
||||
{ oneTimeCallback: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Playing animation to beginning
|
||||
* with a duration of 0 prevents
|
||||
* any flickering when the animation
|
||||
* is later cleaned up.
|
||||
*/
|
||||
ani.progressEnd(0, 0, 0);
|
||||
} else {
|
||||
this.sbAni = ani;
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
const mode = getIonMode(this);
|
||||
const enteringEl = enteringView.element!;
|
||||
const leavingEl = leavingView && leavingView.element!;
|
||||
@@ -1008,15 +1037,16 @@ export class Nav implements NavOutlet {
|
||||
|
||||
private canStart(): boolean {
|
||||
return (
|
||||
!this.gestureOrAnimationInProgress &&
|
||||
!!this.swipeGesture &&
|
||||
!this.isTransitioning &&
|
||||
this.transInstr.length === 0 &&
|
||||
this.animationEnabled &&
|
||||
this.canGoBackSync()
|
||||
);
|
||||
}
|
||||
|
||||
private onStart() {
|
||||
this.gestureOrAnimationInProgress = true;
|
||||
this.pop({ direction: 'back', progressAnimation: true });
|
||||
}
|
||||
|
||||
@@ -1028,10 +1058,9 @@ export class Nav implements NavOutlet {
|
||||
|
||||
private onEnd(shouldComplete: boolean, stepValue: number, dur: number) {
|
||||
if (this.sbAni) {
|
||||
this.animationEnabled = false;
|
||||
this.sbAni.onFinish(
|
||||
() => {
|
||||
this.animationEnabled = true;
|
||||
this.gestureOrAnimationInProgress = false;
|
||||
},
|
||||
{ oneTimeCallback: true }
|
||||
);
|
||||
@@ -1055,6 +1084,8 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
|
||||
this.sbAni.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
|
||||
} else {
|
||||
this.gestureOrAnimationInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
|
||||
import { raf } from '@utils/helpers';
|
||||
import {
|
||||
createDelegateController,
|
||||
createTriggerController,
|
||||
@@ -199,6 +200,16 @@ export class Picker implements ComponentInterface, OverlayInterface {
|
||||
setOverlayId(this.el);
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
/**
|
||||
* If picker was rendered with isOpen="true"
|
||||
* then we should open picker immediately.
|
||||
*/
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the picker overlay after it has been created.
|
||||
*/
|
||||
|
||||
@@ -23,5 +23,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
await ionPickerDidDismiss.next();
|
||||
await expect(picker).toBeHidden();
|
||||
});
|
||||
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-picker is-open="true"></ion-picker>', config);
|
||||
await expect(page.locator('ion-picker')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
11
core/src/components/popover/test/is-open/popover.e2e.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('popover: isOpen'), () => {
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-popover is-open="true"></ion-popover>', config);
|
||||
await expect(page.locator('ion-popover')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
@import "./select-popover";
|
||||
@import "./select-popover.md.vars";
|
||||
|
||||
ion-list ion-radio {
|
||||
ion-list ion-radio::part(container) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ComponentInterface } from '@stencil/core';
|
||||
import { Element, Component, Host, Prop, h } from '@stencil/core';
|
||||
import { Element, Component, Host, Prop, h, forceUpdate } from '@stencil/core';
|
||||
import { safeCall } from '@utils/overlays';
|
||||
import { getClassMap } from '@utils/theme';
|
||||
|
||||
@@ -116,19 +116,28 @@ export class SelectPopover implements ComponentInterface {
|
||||
|
||||
renderCheckboxOptions(options: SelectPopoverOption[]) {
|
||||
return options.map((option) => (
|
||||
<ion-item class={getClassMap(option.cssClass)}>
|
||||
<ion-item
|
||||
class={{
|
||||
// TODO FW-4784
|
||||
'item-checkbox-checked': option.checked,
|
||||
...getClassMap(option.cssClass),
|
||||
}}
|
||||
>
|
||||
<ion-checkbox
|
||||
slot="start"
|
||||
value={option.value}
|
||||
disabled={option.disabled}
|
||||
checked={option.checked}
|
||||
legacy={true}
|
||||
justify="start"
|
||||
labelPlacement="end"
|
||||
onIonChange={(ev) => {
|
||||
this.setChecked(ev);
|
||||
this.callOptionHandler(ev);
|
||||
// TODO FW-4784
|
||||
forceUpdate(this);
|
||||
}}
|
||||
></ion-checkbox>
|
||||
<ion-label>{option.text}</ion-label>
|
||||
>
|
||||
{option.text}
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
));
|
||||
}
|
||||
@@ -139,12 +148,16 @@ export class SelectPopover implements ComponentInterface {
|
||||
return (
|
||||
<ion-radio-group value={checked} onIonChange={(ev) => this.callOptionHandler(ev)}>
|
||||
{options.map((option) => (
|
||||
<ion-item class={getClassMap(option.cssClass)}>
|
||||
<ion-label>{option.text}</ion-label>
|
||||
<ion-item
|
||||
class={{
|
||||
// TODO FW-4784
|
||||
'item-radio-checked': option.value === checked,
|
||||
...getClassMap(option.cssClass),
|
||||
}}
|
||||
>
|
||||
<ion-radio
|
||||
value={option.value}
|
||||
disabled={option.disabled}
|
||||
legacy={true}
|
||||
onClick={() => this.dismissParentPopover()}
|
||||
onKeyUp={(ev) => {
|
||||
if (ev.key === ' ') {
|
||||
@@ -156,7 +169,9 @@ export class SelectPopover implements ComponentInterface {
|
||||
this.dismissParentPopover();
|
||||
}
|
||||
}}
|
||||
></ion-radio>
|
||||
>
|
||||
{option.text}
|
||||
</ion-radio>
|
||||
</ion-item>
|
||||
))}
|
||||
</ion-radio-group>
|
||||
|
||||
@@ -81,11 +81,11 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
selectPopoverPage = new SelectPopoverPage(page);
|
||||
});
|
||||
test('should not have visual regressions with single selection', async () => {
|
||||
await selectPopoverPage.setup(config, options, false);
|
||||
await selectPopoverPage.setup(config, checkedOptions, false);
|
||||
await selectPopoverPage.screenshot(screenshot, 'select-popover-diff');
|
||||
});
|
||||
test('should not have visual regressions with multiple selection', async () => {
|
||||
await selectPopoverPage.setup(config, options, true);
|
||||
await selectPopoverPage.setup(config, checkedOptions, true);
|
||||
await selectPopoverPage.screenshot(screenshot, 'select-popover-multiple-diff');
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -302,4 +302,27 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
||||
await expect(page.locator('.container')).toHaveScreenshot(screenshot(`textarea-multi-line-sizing`));
|
||||
});
|
||||
});
|
||||
test.describe(title('textarea: floating/stacked label layering'), () => {
|
||||
test('label should not be covered by text field', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/27812',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
.custom-textarea .native-wrapper {
|
||||
background: pink;
|
||||
}
|
||||
</style>
|
||||
<ion-textarea class="custom-textarea" label="My Label" label-placement="stacked"></ion-textarea>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const textarea = page.locator('ion-textarea');
|
||||
|
||||
expect(await textarea.screenshot()).toMatchSnapshot(screenshot(`textarea-label-layering`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
@@ -82,8 +82,6 @@
|
||||
:host(.textarea-fill-outline) .label-text-wrapper,
|
||||
:host(.textarea-fill-outline) .label-text-wrapper {
|
||||
position: relative;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -629,6 +629,13 @@
|
||||
@include padding(0px);
|
||||
|
||||
max-width: 100%;
|
||||
|
||||
/**
|
||||
* The 2 ensures the label
|
||||
* remains on top of any browser
|
||||
* autofill background too.
|
||||
*/
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,5 +24,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
await ionToastDidDismiss.next();
|
||||
await expect(toast).toBeHidden();
|
||||
});
|
||||
|
||||
test('should open if isOpen is true on load', async ({ page }) => {
|
||||
await page.setContent('<ion-toast is-open="true"></ion-toast>', config);
|
||||
await expect(page.locator('ion-toast')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { State, Watch, Component, Element, Event, h, Host, Method, Prop } from '@stencil/core';
|
||||
import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config';
|
||||
import { raf } from '@utils/helpers';
|
||||
import { printIonWarning } from '@utils/logging';
|
||||
import {
|
||||
createDelegateController,
|
||||
@@ -253,6 +254,16 @@ export class Toast implements ComponentInterface, OverlayInterface {
|
||||
setOverlayId(this.el);
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
/**
|
||||
* If toast was rendered with isOpen="true"
|
||||
* then we should open toast immediately.
|
||||
*/
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the toast overlay after it has been created.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
4
docs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"types": "core.d.ts",
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"docs",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "7.2.1"
|
||||
"version": "7.2.3"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
18
packages/angular-server/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1"
|
||||
"@ionic/core": "^7.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-eslint/eslint-plugin": "^14.0.0",
|
||||
@@ -1060,9 +1060,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -7342,9 +7342,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -61,6 +61,6 @@
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1"
|
||||
"@ionic/core": "^7.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
18
packages/angular/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1",
|
||||
"@ionic/core": "^7.2.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
@@ -1227,9 +1227,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -8104,9 +8104,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1",
|
||||
"@ionic/core": "^7.2.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **react, vue:** custom animations are used when going back ([#27895](https://github.com/ionic-team/ionic-framework/issues/27895)) ([824033f](https://github.com/ionic-team/ionic-framework/commit/824033f1d4b4a3e5d4c6a978a39e5bb1f33b5bb4)), closes [#27873](https://github.com/ionic-team/ionic-framework/issues/27873)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
34
packages/react-router/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react-router",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/react": "^7.2.1",
|
||||
"@ionic/react": "^7.2.3",
|
||||
"tslib": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -205,9 +205,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -401,11 +401,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.2.1.tgz",
|
||||
"integrity": "sha512-z9PSPoBiHsdwotdywGcnln1y01wjLoS09vmCUboc+2qSadVMczcjEuBxfRIvjVbaQt3u8RGHif2+K3AgGNKMeA==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.2.2.tgz",
|
||||
"integrity": "sha512-QFvLTCw/9/7aBFooRUZFD/pIOLgMO5E7AzW9DeJoyjenVp3TBbhKvlz275+2Z4Nmj82nXMZs2xWnmuzgweb2sQ==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "7.2.1",
|
||||
"@ionic/core": "7.2.2",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@@ -3663,9 +3663,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -3786,11 +3786,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/react": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.2.1.tgz",
|
||||
"integrity": "sha512-z9PSPoBiHsdwotdywGcnln1y01wjLoS09vmCUboc+2qSadVMczcjEuBxfRIvjVbaQt3u8RGHif2+K3AgGNKMeA==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.2.2.tgz",
|
||||
"integrity": "sha512-QFvLTCw/9/7aBFooRUZFD/pIOLgMO5E7AzW9DeJoyjenVp3TBbhKvlz275+2Z4Nmj82nXMZs2xWnmuzgweb2sQ==",
|
||||
"requires": {
|
||||
"@ionic/core": "7.2.1",
|
||||
"@ionic/core": "7.2.2",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "React Router wrapper for @ionic/react",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -37,7 +37,7 @@
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/react": "^7.2.1",
|
||||
"@ionic/react": "^7.2.3",
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { RouteInfo, StackContextState, ViewItem } from '@ionic/react';
|
||||
import { RouteManagerContext, StackContext, generateId, getConfig } from '@ionic/react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { cloneElement, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
||||
import React from 'react';
|
||||
import { matchPath } from 'react-router-dom';
|
||||
|
||||
import { clonePageElement } from './clonePageElement';
|
||||
@@ -12,93 +11,76 @@ interface StackManagerProps {
|
||||
routeInfo: RouteInfo;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface StackManagerState {}
|
||||
|
||||
const isViewVisible = (el: HTMLElement) =>
|
||||
!el.classList.contains('ion-page-invisible') && !el.classList.contains('ion-page-hidden');
|
||||
|
||||
export const StackManager = ({ children, ...props }: PropsWithChildren<StackManagerProps>) => {
|
||||
const { routeInfo } = props;
|
||||
const {
|
||||
findViewItemByRouteInfo,
|
||||
findLeavingViewItemByRouteInfo,
|
||||
findViewItemByPathname,
|
||||
createViewItem,
|
||||
addViewItem,
|
||||
goBack,
|
||||
getChildrenToRender,
|
||||
clearOutlet,
|
||||
} = useContext(RouteManagerContext);
|
||||
export class StackManager extends React.PureComponent<StackManagerProps, StackManagerState> {
|
||||
id: string;
|
||||
context!: React.ContextType<typeof RouteManagerContext>;
|
||||
ionRouterOutlet?: React.ReactElement;
|
||||
routerOutletElement: HTMLIonRouterOutletElement | undefined;
|
||||
prevProps?: StackManagerProps;
|
||||
skipTransition: boolean;
|
||||
|
||||
const routerOutletRef = useRef<HTMLIonRouterOutletElement>();
|
||||
const ionRouterOutletRef = useRef<React.ReactElement>();
|
||||
const skipTransitionRef = useRef(false);
|
||||
const clearOutletTimeout = useRef(null);
|
||||
const pendingPageTransitionRef = useRef(false);
|
||||
const prevProps = useRef<{ routeInfo: RouteInfo }>();
|
||||
stackContextValue: StackContextState = {
|
||||
registerIonPage: this.registerIonPage.bind(this),
|
||||
isInOutlet: () => true,
|
||||
};
|
||||
|
||||
const forceUpdate = useReducer((x) => x + 1, 0)[1];
|
||||
private clearOutletTimeout: any;
|
||||
private pendingPageTransition = false;
|
||||
|
||||
const [id] = useState(generateId('routerOutlet'));
|
||||
constructor(props: StackManagerProps) {
|
||||
super(props);
|
||||
this.registerIonPage = this.registerIonPage.bind(this);
|
||||
this.transitionPage = this.transitionPage.bind(this);
|
||||
this.handlePageTransition = this.handlePageTransition.bind(this);
|
||||
this.id = generateId('routerOutlet');
|
||||
this.prevProps = undefined;
|
||||
this.skipTransition = false;
|
||||
}
|
||||
|
||||
const stackContextValue: StackContextState = useMemo(
|
||||
() => ({
|
||||
isInOutlet: () => true,
|
||||
registerIonPage: (page: HTMLElement, routeInfo: RouteInfo) => {
|
||||
const foundView = findViewItemByRouteInfo(routeInfo, id);
|
||||
if (foundView) {
|
||||
const oldPageElement = foundView.ionPageElement;
|
||||
foundView.ionPageElement = page;
|
||||
foundView.ionRoute = true;
|
||||
|
||||
/**
|
||||
* React 18 will unmount and remount IonPage
|
||||
* elements in development mode when using createRoot.
|
||||
* This can cause duplicate page transitions to occur.
|
||||
*/
|
||||
if (oldPageElement === page) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
handlePageTransition(routeInfo);
|
||||
},
|
||||
}),
|
||||
[routerOutletRef.current]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
if (routerOutletElement) {
|
||||
// Mount behavior for the initial route
|
||||
setupRouterOutlet(routerOutletElement);
|
||||
|
||||
handlePageTransition(routeInfo);
|
||||
componentDidMount() {
|
||||
if (this.clearOutletTimeout) {
|
||||
/**
|
||||
* The clearOutlet integration with React Router is a bit hacky.
|
||||
* It uses a timeout to clear the outlet after a transition.
|
||||
* In React v18, components are mounted and unmounted in development mode
|
||||
* to check for side effects.
|
||||
*
|
||||
* This clearTimeout prevents the outlet from being cleared when the component is re-mounted,
|
||||
* which should only happen in development mode and as a result of a hot reload.
|
||||
*/
|
||||
clearTimeout(this.clearOutletTimeout);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const { pathname } = routeInfo;
|
||||
|
||||
if (pathname !== prevProps.current?.routeInfo.pathname) {
|
||||
prevProps.current = props;
|
||||
handlePageTransition(routeInfo);
|
||||
} else if (pendingPageTransitionRef.current) {
|
||||
handlePageTransition(routeInfo);
|
||||
pendingPageTransitionRef.current = false;
|
||||
if (this.routerOutletElement) {
|
||||
this.setupRouterOutlet(this.routerOutletElement);
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
}
|
||||
}, [routeInfo]);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearOutlet(id);
|
||||
if (clearOutletTimeout.current) {
|
||||
clearTimeout(clearOutletTimeout.current);
|
||||
clearOutletTimeout.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
componentDidUpdate(prevProps: StackManagerProps) {
|
||||
const { pathname } = this.props.routeInfo;
|
||||
const { pathname: prevPathname } = prevProps.routeInfo;
|
||||
|
||||
const handlePageTransition = (routeInfo: RouteInfo) => {
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
if (!routerOutletElement || !routerOutletElement.commit) {
|
||||
if (pathname !== prevPathname) {
|
||||
this.prevProps = prevProps;
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
} else if (this.pendingPageTransition) {
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
this.pendingPageTransition = false;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearOutletTimeout = this.context.clearOutlet(this.id);
|
||||
}
|
||||
|
||||
async handlePageTransition(routeInfo: RouteInfo) {
|
||||
if (!this.routerOutletElement || !this.routerOutletElement.commit) {
|
||||
/**
|
||||
* The route outlet has not mounted yet. We need to wait for it to render
|
||||
* before we can transition the page.
|
||||
@@ -106,126 +88,142 @@ export const StackManager = ({ children, ...props }: PropsWithChildren<StackMana
|
||||
* Set a flag to indicate that we should transition the page after
|
||||
* the component has updated.
|
||||
*/
|
||||
pendingPageTransitionRef.current = true;
|
||||
return;
|
||||
}
|
||||
this.pendingPageTransition = true;
|
||||
} else {
|
||||
let enteringViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
let leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id);
|
||||
|
||||
let enteringViewItem = findViewItemByRouteInfo(routeInfo, id);
|
||||
let leavingViewItem = findLeavingViewItemByRouteInfo(routeInfo, id);
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = this.context.findViewItemByPathname(routeInfo.prevRouteLastPathname, this.id);
|
||||
}
|
||||
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = findViewItemByPathname(routeInfo.prevRouteLastPathname, id);
|
||||
}
|
||||
|
||||
// Check if the leavingViewItem should be unmounted
|
||||
if (leavingViewItem) {
|
||||
if (routeInfo.routeAction === 'replace') {
|
||||
leavingViewItem.mount = false;
|
||||
} else if (!(routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward')) {
|
||||
if (routeInfo.routeDirection !== 'none' && enteringViewItem !== leavingViewItem) {
|
||||
// Check if leavingViewItem should be unmounted
|
||||
if (leavingViewItem) {
|
||||
if (routeInfo.routeAction === 'replace') {
|
||||
leavingViewItem.mount = false;
|
||||
} else if (!(routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward')) {
|
||||
if (routeInfo.routeDirection !== 'none' && enteringViewItem !== leavingViewItem) {
|
||||
leavingViewItem.mount = false;
|
||||
}
|
||||
} else if (routeInfo.routeOptions?.unmount) {
|
||||
leavingViewItem.mount = false;
|
||||
}
|
||||
} else if (routeInfo.routeOptions?.unmount) {
|
||||
leavingViewItem.mount = false;
|
||||
}
|
||||
}
|
||||
|
||||
const enteringRoute = matchRoute(ionRouterOutletRef.current?.props.children, routeInfo) as React.ReactElement;
|
||||
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
||||
|
||||
if (enteringViewItem) {
|
||||
// If the entering view is already in the stack, then we need to clone it
|
||||
enteringViewItem.reactElement = enteringRoute;
|
||||
} else if (enteringRoute) {
|
||||
// Otherwise we need to create a new view item
|
||||
enteringViewItem = createViewItem(id, enteringRoute, routeInfo);
|
||||
addViewItem(enteringViewItem);
|
||||
}
|
||||
if (enteringViewItem) {
|
||||
enteringViewItem.reactElement = enteringRoute;
|
||||
} else if (enteringRoute) {
|
||||
enteringViewItem = this.context.createViewItem(this.id, enteringRoute, routeInfo);
|
||||
this.context.addViewItem(enteringViewItem);
|
||||
}
|
||||
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement) {
|
||||
/**
|
||||
* If the entering view item is the same as the leaving view item,
|
||||
* then we don't need to transition.
|
||||
*/
|
||||
if (enteringViewItem === leavingViewItem) {
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement) {
|
||||
/**
|
||||
* If the entering view item is the same as the leaving view item,
|
||||
* we are either transitioning using parameterized routes to the same view
|
||||
* or a parent router outlet is re-rendering as a result of React props changing.
|
||||
*
|
||||
* If the route data does not match the current path, the parent router outlet
|
||||
* is attempting to transition and we cancel the operation.
|
||||
* then we don't need to transition.
|
||||
*/
|
||||
if (enteringViewItem.routeData.match.url !== routeInfo.pathname) {
|
||||
if (enteringViewItem === leavingViewItem) {
|
||||
/**
|
||||
* If the entering view item is the same as the leaving view item,
|
||||
* we are either transitioning using parameterized routes to the same view
|
||||
* or a parent router outlet is re-rendering as a result of React props changing.
|
||||
*
|
||||
* If the route data does not match the current path, the parent router outlet
|
||||
* is attempting to transition and we cancel the operation.
|
||||
*/
|
||||
if (enteringViewItem.routeData.match.url !== routeInfo.pathname) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there isn't a leaving view item, but the route info indicates
|
||||
* that the user has routed from a previous path, then we need
|
||||
* to find the leaving view item to transition between.
|
||||
*/
|
||||
if (!leavingViewItem && this.props.routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = this.context.findViewItemByPathname(this.props.routeInfo.prevRouteLastPathname, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the entering view is already visible and the leaving view is not, the transition does not need to occur.
|
||||
*/
|
||||
if (
|
||||
isViewVisible(enteringViewItem.ionPageElement) &&
|
||||
leavingViewItem !== undefined &&
|
||||
!isViewVisible(leavingViewItem.ionPageElement!)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The view should only be transitioned in the following cases:
|
||||
* 1. Performing a replace or pop action, such as a swipe to go back gesture
|
||||
* to animation the leaving view off the screen.
|
||||
*
|
||||
* 2. Navigating between top-level router outlets, such as /page-1 to /page-2;
|
||||
* or navigating within a nested outlet, such as /tabs/tab-1 to /tabs/tab-2.
|
||||
*
|
||||
* 3. The entering view is an ion-router-outlet containing a page
|
||||
* matching the current route and that hasn't already transitioned in.
|
||||
*
|
||||
* This should only happen when navigating directly to a nested router outlet
|
||||
* route or on an initial page load (i.e. refreshing). In cases when loading
|
||||
* /tabs/tab-1, we need to transition the /tabs page element into the view.
|
||||
*/
|
||||
this.transitionPage(routeInfo, enteringViewItem, leavingViewItem);
|
||||
} else if (leavingViewItem && !enteringRoute && !enteringViewItem) {
|
||||
// If we have a leavingView but no entering view/route, we are probably leaving to
|
||||
// another outlet, so hide this leavingView. We do it in a timeout to give time for a
|
||||
// transition to finish.
|
||||
// setTimeout(() => {
|
||||
if (leavingViewItem.ionPageElement) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
// }, 250);
|
||||
}
|
||||
|
||||
/**
|
||||
* If there isn't a leaving view item, but the route info indicates
|
||||
* that the user has routed from a previous path, then we need
|
||||
* to find the leaving view item to transition between.
|
||||
*/
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = findViewItemByPathname(routeInfo.prevRouteLastPathname, id);
|
||||
}
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
registerIonPage(page: HTMLElement, routeInfo: RouteInfo) {
|
||||
const foundView = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
if (foundView) {
|
||||
const oldPageElement = foundView.ionPageElement;
|
||||
foundView.ionPageElement = page;
|
||||
foundView.ionRoute = true;
|
||||
|
||||
/**
|
||||
* If the entering view is already visible and the leaving view is not, the transition does not need to occur.
|
||||
* React 18 will unmount and remount IonPage
|
||||
* elements in development mode when using createRoot.
|
||||
* This can cause duplicate page transitions to occur.
|
||||
*/
|
||||
if (
|
||||
isViewVisible(enteringViewItem.ionPageElement) &&
|
||||
leavingViewItem !== undefined &&
|
||||
!isViewVisible(leavingViewItem.ionPageElement!)
|
||||
) {
|
||||
if (oldPageElement === page) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The view should only be transitioned in the following cases:
|
||||
* 1. Performing a replace or pop action, such as a swipe to go back gesture
|
||||
* to animation the leaving view off the screen.
|
||||
*
|
||||
* 2. Navigating between top-level router outlets, such as /page-1 to /page-2;
|
||||
* or navigating within a nested outlet, such as /tabs/tab-1 to /tabs/tab-2.
|
||||
*
|
||||
* 3. The entering view is an ion-router-outlet containing a page
|
||||
* matching the current route and that hasn't already transitioned in.
|
||||
*
|
||||
* This should only happen when navigating directly to a nested router outlet
|
||||
* route or on an initial page load (i.e. refreshing). In cases when loading
|
||||
* /tabs/tab-1, we need to transition the /tabs page element into the view.
|
||||
*/
|
||||
transitionPage(routeInfo, enteringViewItem, leavingViewItem!);
|
||||
} else if (leavingViewItem && !enteringRoute && !enteringViewItem) {
|
||||
// If we have a leavingView but no entering view/route, we are probably leaving to
|
||||
// another outlet, so hide this leavingView.
|
||||
if (leavingViewItem.ionPageElement) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
}
|
||||
this.handlePageTransition(routeInfo);
|
||||
}
|
||||
|
||||
// This causes the router outlet to re-render with the updated view items.
|
||||
// Without it, a push navigation will remove the previous route's view item,
|
||||
// but will not render the new route's view item.
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
const setupRouterOutlet = (routerOutlet: HTMLIonRouterOutletElement) => {
|
||||
const canStart = (): boolean => {
|
||||
async setupRouterOutlet(routerOutlet: HTMLIonRouterOutletElement) {
|
||||
const canStart = () => {
|
||||
const config = getConfig();
|
||||
const swipeEnabled = config?.getBoolean('swipeBackEnabled', routerOutlet.mode === 'ios');
|
||||
|
||||
const swipeEnabled = config && config.get('swipeBackEnabled', routerOutlet.mode === 'ios');
|
||||
if (!swipeEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const propsToUse =
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
|
||||
return (
|
||||
!!enteringViewItem &&
|
||||
@@ -249,12 +247,14 @@ export const StackManager = ({ children, ...props }: PropsWithChildren<StackMana
|
||||
};
|
||||
|
||||
const onStart = async () => {
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const leavingViewItem = findViewItemByRouteInfo(routeInfo, id, false);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
||||
|
||||
/**
|
||||
* When the gesture starts, kick off
|
||||
@@ -262,28 +262,30 @@ export const StackManager = ({ children, ...props }: PropsWithChildren<StackMana
|
||||
* via a swipe gesture.
|
||||
*/
|
||||
if (enteringViewItem && leavingViewItem) {
|
||||
await transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
||||
await this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const onEnd = (shouldContinue: boolean) => {
|
||||
if (shouldContinue) {
|
||||
skipTransitionRef.current = true;
|
||||
goBack();
|
||||
this.skipTransition = true;
|
||||
|
||||
this.context.goBack();
|
||||
} else {
|
||||
/**
|
||||
* In the event that the swipe
|
||||
* gesture was aborted, we should
|
||||
* re-hide the page that was going to enter.
|
||||
*/
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const leavingViewItem = findViewItemByRouteInfo(routeInfo, id, false);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
||||
|
||||
/**
|
||||
* Ionic React has a design defect where it
|
||||
@@ -307,17 +309,17 @@ export const StackManager = ({ children, ...props }: PropsWithChildren<StackMana
|
||||
onStart,
|
||||
onEnd,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const transitionPage = async (
|
||||
async transitionPage(
|
||||
routeInfo: RouteInfo,
|
||||
enteringViewItem: ViewItem,
|
||||
leavingViewItem: ViewItem,
|
||||
leavingViewItem?: ViewItem,
|
||||
direction?: 'forward' | 'back',
|
||||
progressAnimation = false
|
||||
) => {
|
||||
) {
|
||||
const runCommit = async (enteringEl: HTMLElement, leavingEl?: HTMLElement) => {
|
||||
const skipTransition = skipTransitionRef.current;
|
||||
const skipTransition = this.skipTransition;
|
||||
|
||||
/**
|
||||
* If the transition was handled
|
||||
@@ -340,99 +342,102 @@ export const StackManager = ({ children, ...props }: PropsWithChildren<StackMana
|
||||
* transition triggered by handlePageTransition
|
||||
* in componentDidUpdate.
|
||||
*/
|
||||
skipTransitionRef.current = false;
|
||||
this.skipTransition = false;
|
||||
} else {
|
||||
enteringEl.classList.add('ion-page', 'ion-page-invisible');
|
||||
enteringEl.classList.add('ion-page');
|
||||
enteringEl.classList.add('ion-page-invisible');
|
||||
}
|
||||
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
|
||||
if (routerOutletElement) {
|
||||
await routerOutletElement.commit(enteringEl, leavingEl, {
|
||||
duration: skipTransitionRef.current || directionToUse === undefined ? 0 : undefined,
|
||||
direction: directionToUse,
|
||||
showGoBack: !!routeInfo.pushedByRoute,
|
||||
progressAnimation,
|
||||
animationBuilder: routeInfo.routeAnimation,
|
||||
});
|
||||
}
|
||||
await routerOutlet.commit(enteringEl, leavingEl, {
|
||||
duration: skipTransition || directionToUse === undefined ? 0 : undefined,
|
||||
direction: directionToUse,
|
||||
showGoBack: !!routeInfo.pushedByRoute,
|
||||
progressAnimation,
|
||||
animationBuilder: routeInfo.routeAnimation,
|
||||
});
|
||||
};
|
||||
|
||||
const routerInfoFallbackDirection =
|
||||
const routerOutlet = this.routerOutletElement!;
|
||||
|
||||
const routeInfoFallbackDirection =
|
||||
routeInfo.routeDirection === 'none' || routeInfo.routeDirection === 'root' ? undefined : routeInfo.routeDirection;
|
||||
const directionToUse = direction ?? routerInfoFallbackDirection;
|
||||
const directionToUse = direction ?? routeInfoFallbackDirection;
|
||||
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
|
||||
if (enteringViewItem?.ionPageElement && routerOutletElement) {
|
||||
if (leavingViewItem?.ionPageElement && enteringViewItem === leavingViewItem) {
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement && this.routerOutletElement) {
|
||||
if (leavingViewItem && leavingViewItem.ionPageElement && enteringViewItem === leavingViewItem) {
|
||||
// If a page is transitioning to another version of itself
|
||||
// we clone it so we can have an animation to show
|
||||
|
||||
const match = matchComponent(leavingViewItem.reactElement, routeInfo.pathname, true);
|
||||
if (match) {
|
||||
const newLeavingElement = clonePageElement(leavingViewItem.ionPageElement.outerHTML);
|
||||
if (newLeavingElement) {
|
||||
routerOutletElement.appendChild(newLeavingElement);
|
||||
this.routerOutletElement.appendChild(newLeavingElement);
|
||||
await runCommit(enteringViewItem.ionPageElement, newLeavingElement);
|
||||
routerOutletElement.removeChild(newLeavingElement);
|
||||
this.routerOutletElement.removeChild(newLeavingElement);
|
||||
}
|
||||
} else {
|
||||
await runCommit(enteringViewItem.ionPageElement, undefined);
|
||||
}
|
||||
} else {
|
||||
await runCommit(enteringViewItem.ionPageElement, leavingViewItem?.ionPageElement);
|
||||
if (leavingViewItem?.ionPageElement && !progressAnimation) {
|
||||
const { ionPageElement } = leavingViewItem;
|
||||
ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
ionPageElement.classList.add('ion-page-hidden');
|
||||
if (leavingViewItem && leavingViewItem.ionPageElement && !progressAnimation) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const renderComponents = () => {
|
||||
const ionRouterOutlet = React.Children.only<React.ReactElement>(children as React.ReactElement);
|
||||
ionRouterOutletRef.current = ionRouterOutlet;
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const ionRouterOutlet = React.Children.only(children) as React.ReactElement;
|
||||
this.ionRouterOutlet = ionRouterOutlet;
|
||||
|
||||
const components = getChildrenToRender(id, ionRouterOutlet, routeInfo, () => {
|
||||
forceUpdate();
|
||||
const components = this.context.getChildrenToRender(this.id, this.ionRouterOutlet, this.props.routeInfo, () => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
|
||||
return cloneElement(ionRouterOutlet, {
|
||||
ref: (node: HTMLIonRouterOutletElement) => {
|
||||
if (ionRouterOutlet.props.setRef) {
|
||||
ionRouterOutlet.props.setRef(node);
|
||||
}
|
||||
if (ionRouterOutlet.props.forwardedRef) {
|
||||
ionRouterOutlet.props.forwardedRef.current = node;
|
||||
}
|
||||
return (
|
||||
<StackContext.Provider value={this.stackContextValue}>
|
||||
{React.cloneElement(
|
||||
ionRouterOutlet as any,
|
||||
{
|
||||
ref: (node: HTMLIonRouterOutletElement) => {
|
||||
if (ionRouterOutlet.props.setRef) {
|
||||
ionRouterOutlet.props.setRef(node);
|
||||
}
|
||||
if (ionRouterOutlet.props.forwardedRef) {
|
||||
ionRouterOutlet.props.forwardedRef.current = node;
|
||||
}
|
||||
this.routerOutletElement = node;
|
||||
const { ref } = ionRouterOutlet as any;
|
||||
if (typeof ref === 'function') {
|
||||
ref(node);
|
||||
}
|
||||
},
|
||||
},
|
||||
components
|
||||
)}
|
||||
</StackContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
routerOutletRef.current = node;
|
||||
|
||||
const { ref } = ionRouterOutlet as any;
|
||||
if (typeof ref === 'function') {
|
||||
ref(node);
|
||||
}
|
||||
},
|
||||
components,
|
||||
});
|
||||
};
|
||||
|
||||
return <StackContext.Provider value={stackContextValue}>{renderComponents()}</StackContext.Provider>;
|
||||
};
|
||||
static get contextType() {
|
||||
return RouteManagerContext;
|
||||
}
|
||||
}
|
||||
|
||||
export default StackManager;
|
||||
|
||||
function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
||||
let matchedNode: React.ReactNode;
|
||||
|
||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||
const matchProps = {
|
||||
exact: child.props.exact,
|
||||
path: child.props.path || child.props.from,
|
||||
component: child.props.component,
|
||||
};
|
||||
// In React Router v6 the prop arguments are in a different order
|
||||
const match = matchPath(routeInfo.pathname, matchProps);
|
||||
if (match) {
|
||||
matchedNode = child;
|
||||
@@ -459,7 +464,6 @@ function matchComponent(node: React.ReactElement, pathname: string, forceExact?:
|
||||
path: node.props.path || node.props.from,
|
||||
component: node.props.component,
|
||||
};
|
||||
// In React Router v6 the prop arguments are in a different order
|
||||
const match = matchPath(pathname, matchProps);
|
||||
|
||||
return match;
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tab-button:** update event type interface on React ([#27950](https://github.com/ionic-team/ionic-framework/issues/27950)) ([1cf1eca](https://github.com/ionic-team/ionic-framework/commit/1cf1eca00239f3e98854466116e42f9a2e7b4590)), closes [#27949](https://github.com/ionic-team/ionic-framework/issues/27949)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
||||
18
packages/react/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1",
|
||||
"@ionic/core": "^7.2.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@@ -697,9 +697,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -11778,9 +11778,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "React specific wrapper for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -41,7 +41,7 @@
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1",
|
||||
"@ionic/core": "^7.2.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ type Props = LocalJSX.IonTabButton &
|
||||
IonicReactProps & {
|
||||
routerOptions?: RouterOptions;
|
||||
ref?: React.Ref<HTMLIonTabButtonElement>;
|
||||
onClick?: (e: Event) => void;
|
||||
onClick?: (e: CustomEvent) => void;
|
||||
};
|
||||
|
||||
export const IonTabButton = /*@__PURE__*/ (() =>
|
||||
|
||||
30
packages/react/test/apps/react18/index.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Ionic App</title>
|
||||
|
||||
<base href="/" />
|
||||
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="msapplication-tap-highlight" content="no" />
|
||||
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
|
||||
<!-- add to homescreen for ios -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-title" content="Ionic App" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
25518
packages/react/test/apps/react18/package-lock.json
generated
@@ -3,59 +3,44 @@
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ionic/react": "^6.6.1",
|
||||
"@ionic/react-router": "^6.6.1",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-router": "^5.1.20",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"ionicons": "^6.0.4",
|
||||
"@ionic/react": "^7.0.0",
|
||||
"@ionic/react-router": "^7.0.0",
|
||||
"ionicons": "^7.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^5.3.4",
|
||||
"react-router-dom": "^5.3.4",
|
||||
"react-scripts": "^5.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
"react-router-dom": "^5.3.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'",
|
||||
"eject": "react-scripts eject",
|
||||
"dev": "vite",
|
||||
"start": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"test": "vitest",
|
||||
"sync": "sh ./scripts/sync.sh",
|
||||
"cypress": "cypress run --headless --browser chrome",
|
||||
"cypress.open": "cypress open",
|
||||
"e2e": "concurrently \"serve -s build -l 3000\" \"wait-on http-get://localhost:3000 && npm run cypress\" --kill-others --success first"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
"e2e": "concurrently \"serve -s dist -l 3000\" \"wait-on http-get://localhost:3000 && npm run cypress\" --kill-others --success first"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/react-router": "^5.1.20",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-legacy": "^4.0.2",
|
||||
"@vitejs/plugin-react": "^4.0.1",
|
||||
"concurrently": "^6.3.0",
|
||||
"cypress": "^10.9.0",
|
||||
"cypress": "^12.7.0",
|
||||
"serve": "^14.0.1",
|
||||
"wait-on": "^6.0.0",
|
||||
"webpack-cli": "^4.9.1"
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"jsdom": "^22.1.0",
|
||||
"typescript": "^5.1.6",
|
||||
"vite": "^4.3.9",
|
||||
"vitest": "^0.32.2"
|
||||
},
|
||||
"description": "An Ionic project",
|
||||
"engines": {
|
||||
|
||||
1
packages/react/test/apps/react18/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
21
packages/react/test/apps/react18/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
9
packages/react/test/apps/react18/tsconfig.node.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
19
packages/react/test/apps/react18/vite.config.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import legacy from '@vitejs/plugin-legacy'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
legacy()
|
||||
],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: './src/setupTests.ts',
|
||||
},
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
})
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **react, vue:** custom animations are used when going back ([#27895](https://github.com/ionic-team/ionic-framework/issues/27895)) ([824033f](https://github.com/ionic-team/ionic-framework/commit/824033f1d4b4a3e5d4c6a978a39e5bb1f33b5bb4)), closes [#27873](https://github.com/ionic-team/ionic-framework/issues/27873)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
34
packages/vue-router/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^7.2.1"
|
||||
"@ionic/vue": "^7.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
@@ -660,9 +660,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -871,11 +871,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/vue": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.2.1.tgz",
|
||||
"integrity": "sha512-l9ucLk1NrAZHXdAT8qrJYArklS7cCok6/Qlq52Kg0+C912sfV3IIEMxjfQw8e6MX0aZGkSYMG/BGLEBqxp6gOw==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.2.2.tgz",
|
||||
"integrity": "sha512-yRdwSg3GZokcIoBZ/ZxPl/ZDLyZsj6cisEg4XqtBAcX3d93rJtzxP4Hq+Ql7CN4hOhcpn1MX8BFLrCK/nSj94g==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "7.2.1",
|
||||
"@ionic/core": "7.2.2",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
},
|
||||
@@ -7697,9 +7697,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -7829,11 +7829,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/vue": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.2.1.tgz",
|
||||
"integrity": "sha512-l9ucLk1NrAZHXdAT8qrJYArklS7cCok6/Qlq52Kg0+C912sfV3IIEMxjfQw8e6MX0aZGkSYMG/BGLEBqxp6gOw==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.2.2.tgz",
|
||||
"integrity": "sha512-yRdwSg3GZokcIoBZ/ZxPl/ZDLyZsj6cisEg4XqtBAcX3d93rJtzxP4Hq+Ql7CN4hOhcpn1MX8BFLrCK/nSj94g==",
|
||||
"requires": {
|
||||
"@ionic/core": "7.2.1",
|
||||
"@ionic/core": "7.2.2",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Vue Router integration for @ionic/vue",
|
||||
"scripts": {
|
||||
"test.spec": "jest",
|
||||
@@ -45,7 +45,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/ionic-team/ionic#readme",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^7.2.1"
|
||||
"@ionic/vue": "^7.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
||||
18
packages/vue/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1",
|
||||
"@ionic/core": "^7.2.3",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -207,9 +207,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -3746,9 +3746,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.2.tgz",
|
||||
"integrity": "sha512-KD+dZrrIpKs1BlE3Ffp05yrejSvurUhr0OWP2P/NRax5Dld8wSZj+ETOMkV8uiIPbOTOUbLaAQ7m5ZXduMCYhQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "7.2.1",
|
||||
"version": "7.2.3",
|
||||
"description": "Vue specific wrapper for @ionic/core",
|
||||
"scripts": {
|
||||
"eslint": "eslint src",
|
||||
@@ -66,7 +66,7 @@
|
||||
"vue-router": "^4.0.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.1",
|
||||
"@ionic/core": "^7.2.3",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
"vetur": {
|
||||
|
||||