mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Merge branch 'main' into next (#29957)
This commit is contained in:
22
CHANGELOG.md
22
CHANGELOG.md
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tabs, tab-bar:** use standalone tab bar in Vue, React ([#29940](https://github.com/ionic-team/ionic-framework/issues/29940)) ([b7b383b](https://github.com/ionic-team/ionic-framework/commit/b7b383bee080b72de2e6307ff9a9a051314c69ed)), closes [#29885](https://github.com/ionic-team/ionic-framework/issues/29885) [#29924](https://github.com/ionic-team/ionic-framework/issues/29924)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segment:** prevent flickering for scrollable on iOS ([#29884](https://github.com/ionic-team/ionic-framework/issues/29884)) ([078ed0b](https://github.com/ionic-team/ionic-framework/commit/078ed0b86a0d8e9f8457481cb739ea214195adce)), closes [#29523](https://github.com/ionic-team/ionic-framework/issues/29523)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/core
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segment:** prevent flickering for scrollable on iOS ([#29884](https://github.com/ionic-team/ionic-framework/issues/29884)) ([078ed0b](https://github.com/ionic-team/ionic-framework/commit/078ed0b86a0d8e9f8457481cb739ea214195adce)), closes [#29523](https://github.com/ionic-team/ionic-framework/issues/29523)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ ion-alert,css-prop,--width,md
|
||||
ion-app,none
|
||||
ion-app,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-app,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||
ion-app,method,setFocus,setFocus(elements: HTMLElement[]) => Promise<void>
|
||||
|
||||
ion-avatar,shadow
|
||||
ion-avatar,prop,mode,"ios" | "md",undefined,false,false
|
||||
|
||||
6
core/package-lock.json
generated
6
core/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.3.1",
|
||||
"lockfileVersion": 3,
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@phosphor-icons/core": "^2.1.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
|
||||
@@ -53,8 +53,19 @@ html.ios.ios {
|
||||
--ionic-global-background-color: var(--background);
|
||||
}
|
||||
|
||||
ion-content button,
|
||||
main button {
|
||||
/**
|
||||
* Button styles should only be applied
|
||||
* to native buttons that are not part of the
|
||||
* Ionic framework.
|
||||
* Otherwise, the styles may not appear correctly
|
||||
* when comparing between testing and production.
|
||||
* This issue occurs only with `scoped` components,
|
||||
* which is why `sc-ion-` is used as a filter,
|
||||
* since this class is specifically added to `scoped`
|
||||
* components.
|
||||
*/
|
||||
ion-content button:not([class*="sc-ion-"]),
|
||||
main button:not([class*="sc-ion-"]) {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
clear: both;
|
||||
@@ -67,8 +78,19 @@ main button {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
ion-content button.expand,
|
||||
main button.expand {
|
||||
/**
|
||||
* Button styles should only be applied
|
||||
* to native buttons that are not part of the
|
||||
* Ionic framework.
|
||||
* Otherwise, the styles may not appear correctly
|
||||
* when comparing between testing and production.
|
||||
* This issue occurs only with `scoped` components,
|
||||
* which is why `sc-ion-` is used as a filter,
|
||||
* since this class is specifically added to `scoped`
|
||||
* components.
|
||||
*/
|
||||
ion-content button.expand:not([class*="sc-ion-"]),
|
||||
main button.expand:not([class*="sc-ion-"]) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
3
core/src/components.d.ts
vendored
3
core/src/components.d.ts
vendored
@@ -324,6 +324,9 @@ export namespace Components {
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Used to set focus on an element that uses `ion-focusable`. Do not use this if focusing the element as a result of a keyboard event as the focus utility should handle this for us. This method should be used when we want to programmatically focus an element as a result of another user action. (Ex: We focus the first element inside of a popover when the user presents it, but the popover is not always presented as a result of keyboard action.)
|
||||
*/
|
||||
"setFocus": (elements: HTMLElement[]) => Promise<void>;
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
|
||||
@@ -17,7 +17,6 @@ export class App implements ComponentInterface {
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Used to set focus on an element that uses `ion-focusable`.
|
||||
* Do not use this if focusing the element as a result of a keyboard
|
||||
* event as the focus utility should handle this for us. This method
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
ion-app > ion-content {
|
||||
--background: #dddddd;
|
||||
}
|
||||
ion-content button {
|
||||
ion-content button.trigger {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
.grid {
|
||||
@@ -57,26 +57,30 @@
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Cover</h2>
|
||||
<button id="cover-trigger">Trigger</button>
|
||||
<button id="cover-trigger" class="trigger">Trigger</button>
|
||||
<ion-popover show-backdrop="false" class="cover-popover" trigger="cover-trigger" size="cover">
|
||||
<ion-content class="ion-padding"> My really really really really long content </ion-content>
|
||||
</ion-popover>
|
||||
</div>
|
||||
<div class="grid-item">
|
||||
<h2>With Event</h2>
|
||||
<button id="event-trigger" onclick="openPopover('event-popover', event, 'false')">Trigger</button>
|
||||
<button id="event-trigger" class="trigger" onclick="openPopover('event-popover', event, 'false')">
|
||||
Trigger
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Auto</h2>
|
||||
<button id="auto-trigger">Trigger</button>
|
||||
<button id="auto-trigger" class="trigger">Trigger</button>
|
||||
<ion-popover show-backdrop="false" class="auto-popover" trigger="auto-trigger">
|
||||
<ion-content class="ion-padding"> My really really really really long content </ion-content>
|
||||
</ion-popover>
|
||||
</div>
|
||||
<div class="grid-item">
|
||||
<h2>No Event</h2>
|
||||
<button id="no-event-trigger" onclick="openPopover('no-event-popover', null, 'true')">Trigger</button>
|
||||
<button id="no-event-trigger" class="trigger" onclick="openPopover('no-event-popover', null, 'true')">
|
||||
Trigger
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -344,21 +344,35 @@ export class Segment implements ComponentInterface {
|
||||
const centeredX = activeButtonLeft - scrollContainerBox.width / 2 + activeButtonBox.width / 2;
|
||||
|
||||
/**
|
||||
* We intentionally use scrollBy here instead of scrollIntoView
|
||||
* newScrollPosition is the absolute scroll position that the
|
||||
* container needs to move to in order to center the active button.
|
||||
* It is calculated by adding the current scroll position
|
||||
* (scrollLeft) to the offset needed to center the button
|
||||
* (centeredX).
|
||||
*/
|
||||
const newScrollPosition = el.scrollLeft + centeredX;
|
||||
|
||||
/**
|
||||
* We intentionally use scrollTo here instead of scrollIntoView
|
||||
* to avoid a WebKit bug where accelerated animations break
|
||||
* when using scrollIntoView. Using scrollIntoView will cause the
|
||||
* segment container to jump during the transition and then snap into place.
|
||||
* This is because scrollIntoView can potentially cause parent element
|
||||
* containers to also scroll. scrollBy does not have this same behavior, so
|
||||
* containers to also scroll. scrollTo does not have this same behavior, so
|
||||
* we use this API instead.
|
||||
*
|
||||
* scrollTo is used instead of scrollBy because there is a
|
||||
* Webkit bug that causes scrollBy to not work smoothly when
|
||||
* the active button is near the edge of the scroll container.
|
||||
* This leads to the buttons to jump around during the transition.
|
||||
*
|
||||
* Note that if there is not enough scrolling space to center the element
|
||||
* within the scroll container, the browser will attempt
|
||||
* to center by as much as it can.
|
||||
*/
|
||||
el.scrollBy({
|
||||
el.scrollTo({
|
||||
top: 0,
|
||||
left: centeredX,
|
||||
left: newScrollPosition,
|
||||
behavior: smoothScroll ? 'smooth' : 'instant',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"core",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "8.3.1"
|
||||
"version": "8.3.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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
18
packages/angular-server/package-lock.json
generated
18
packages/angular-server/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1"
|
||||
"@ionic/core": "^8.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-eslint/eslint-plugin": "^16.0.0",
|
||||
@@ -1031,9 +1031,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -7188,9 +7188,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -62,6 +62,6 @@
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1"
|
||||
"@ionic/core": "^8.3.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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
18
packages/angular/package-lock.json
generated
18
packages/angular/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1",
|
||||
"@ionic/core": "^8.3.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
@@ -1398,9 +1398,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -9820,9 +9820,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1",
|
||||
"@ionic/core": "^8.3.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
|
||||
@@ -188,7 +188,8 @@ Shorthand for ionAlertDidDismiss.
|
||||
|
||||
|
||||
@ProxyCmp({
|
||||
inputs: ['mode', 'theme']
|
||||
inputs: ['mode', 'theme'],
|
||||
methods: ['setFocus']
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-app',
|
||||
|
||||
@@ -267,7 +267,8 @@ Shorthand for ionAlertDidDismiss.
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineIonApp,
|
||||
inputs: ['mode', 'theme']
|
||||
inputs: ['mode', 'theme'],
|
||||
methods: ['setFocus']
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-app',
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
4
packages/docs/package-lock.json
generated
4
packages/docs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/docs",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"types": "core.d.ts",
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
34
packages/react-router/package-lock.json
generated
34
packages/react-router/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react-router",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/react": "^8.3.1",
|
||||
"@ionic/react": "^8.3.3",
|
||||
"tslib": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -238,9 +238,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -414,11 +414,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.3.1.tgz",
|
||||
"integrity": "sha512-5P/EFtJsgXFi505TmhIVIASomLWxUFf1KilCiH9/AZlLvEXFIT5x9o6L061+j+An4j0uR1MbDh/DwnrTYiO0NA==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.3.3.tgz",
|
||||
"integrity": "sha512-BQVke+4QF1viPmwYFV/Bfseh4AhLnA0svP8UvKTP45plJ2KDXF/IbFVNn+FWtjByrqYU4PldUgF01+O4yPGiRw==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "8.3.1",
|
||||
"@ionic/core": "8.3.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@@ -4057,9 +4057,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -4163,11 +4163,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/react": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.3.1.tgz",
|
||||
"integrity": "sha512-5P/EFtJsgXFi505TmhIVIASomLWxUFf1KilCiH9/AZlLvEXFIT5x9o6L061+j+An4j0uR1MbDh/DwnrTYiO0NA==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.3.3.tgz",
|
||||
"integrity": "sha512-BQVke+4QF1viPmwYFV/Bfseh4AhLnA0svP8UvKTP45plJ2KDXF/IbFVNn+FWtjByrqYU4PldUgF01+O4yPGiRw==",
|
||||
"requires": {
|
||||
"@ionic/core": "8.3.1",
|
||||
"@ionic/core": "8.3.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "React Router wrapper for @ionic/react",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -36,7 +36,7 @@
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/react": "^8.3.1",
|
||||
"@ionic/react": "^8.3.3",
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tabs, tab-bar:** use standalone tab bar in Vue, React ([#29940](https://github.com/ionic-team/ionic-framework/issues/29940)) ([b7b383b](https://github.com/ionic-team/ionic-framework/commit/b7b383bee080b72de2e6307ff9a9a051314c69ed)), closes [#29885](https://github.com/ionic-team/ionic-framework/issues/29885) [#29924](https://github.com/ionic-team/ionic-framework/issues/29924)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
|
||||
|
||||
18
packages/react/package-lock.json
generated
18
packages/react/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1",
|
||||
"@ionic/core": "^8.3.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@@ -736,9 +736,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -12315,9 +12315,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "React specific wrapper for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -39,7 +39,7 @@
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1",
|
||||
"@ionic/core": "^8.3.3",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
|
||||
@@ -8,6 +8,8 @@ import { IonTabBarInner } from '../inner-proxies';
|
||||
import { createForwardRef } from '../utils';
|
||||
|
||||
import { IonTabButton } from './IonTabButton';
|
||||
import { IonTabsContext } from './IonTabsContext';
|
||||
import type { IonTabsContextState } from './IonTabsContext';
|
||||
|
||||
type IonTabBarProps = LocalJSX.IonTabBar &
|
||||
IonicReactProps & {
|
||||
@@ -21,7 +23,7 @@ interface InternalProps extends IonTabBarProps {
|
||||
forwardedRef?: React.ForwardedRef<HTMLIonIconElement>;
|
||||
onSetCurrentTab: (tab: string, routeInfo: RouteInfo) => void;
|
||||
routeInfo: RouteInfo;
|
||||
routerOutletRef?: React.RefObject<HTMLIonRouterOutletElement> | undefined;
|
||||
tabsContext?: IonTabsContextState;
|
||||
}
|
||||
|
||||
interface TabUrls {
|
||||
@@ -183,12 +185,14 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
|
||||
) {
|
||||
const tappedTab = this.state.tabs[e.detail.tab];
|
||||
const originalHref = tappedTab.originalHref;
|
||||
const hasRouterOutlet = this.props.tabsContext?.hasRouterOutlet;
|
||||
|
||||
/**
|
||||
* If the router outlet is not defined, then the tabs is being used
|
||||
* as a basic tab navigation without the router. In this case, we
|
||||
* don't want to update the href else the URL will change.
|
||||
*/
|
||||
const currentHref = this.props.routerOutletRef?.current ? e.detail.href : '';
|
||||
const currentHref = hasRouterOutlet ? e.detail.href : '';
|
||||
const { activeTab: prevActiveTab } = this.state;
|
||||
|
||||
if (onClickFn) {
|
||||
@@ -212,7 +216,7 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
|
||||
if (this.props.onIonTabsDidChange) {
|
||||
this.props.onIonTabsDidChange(new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } }));
|
||||
}
|
||||
if (this.props.routerOutletRef?.current) {
|
||||
if (hasRouterOutlet) {
|
||||
this.setActiveTabOnContext(e.detail.tab);
|
||||
this.context.changeTab(e.detail.tab, currentHref, e.detail.routeOptions);
|
||||
}
|
||||
@@ -262,12 +266,29 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
|
||||
|
||||
const IonTabBarContainer: React.FC<InternalProps> = React.memo<InternalProps>(({ forwardedRef, ...props }) => {
|
||||
const context = useContext(NavContext);
|
||||
const tabsContext = useContext(IonTabsContext);
|
||||
const tabBarRef = forwardedRef || tabsContext.tabBarProps.ref;
|
||||
const updatedTabBarProps = {
|
||||
...tabsContext.tabBarProps,
|
||||
ref: tabBarRef,
|
||||
};
|
||||
|
||||
return (
|
||||
<IonTabBarUnwrapped
|
||||
ref={forwardedRef}
|
||||
ref={tabBarRef}
|
||||
{...(props as any)}
|
||||
routeInfo={props.routeInfo || context.routeInfo || { pathname: window.location.pathname }}
|
||||
onSetCurrentTab={context.setCurrentTab}
|
||||
/**
|
||||
* Tab bar can be used as a standalone component,
|
||||
* so it cannot be modified directly through
|
||||
* IonTabs. Instead, props will be passed through
|
||||
* the context.
|
||||
*/
|
||||
tabsContext={{
|
||||
...tabsContext,
|
||||
tabBarProps: updatedTabBarProps,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</IonTabBarUnwrapped>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { IonRouterOutlet } from '../IonRouterOutlet';
|
||||
import { IonTabsInner } from '../inner-proxies';
|
||||
import { IonTab } from '../proxies';
|
||||
|
||||
import { IonTabBar } from './IonTabBar';
|
||||
import type { IonTabsContextState } from './IonTabsContext';
|
||||
import { IonTabsContext } from './IonTabsContext';
|
||||
|
||||
@@ -43,28 +42,15 @@ interface Props extends LocalJSX.IonTabs {
|
||||
children: ChildFunction | React.ReactNode;
|
||||
}
|
||||
|
||||
const hostStyles: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
position: 'absolute',
|
||||
top: '0',
|
||||
left: '0',
|
||||
right: '0',
|
||||
bottom: '0',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
contain: 'layout size style',
|
||||
};
|
||||
|
||||
const tabsInner: React.CSSProperties = {
|
||||
position: 'relative',
|
||||
flex: 1,
|
||||
contain: 'layout size style',
|
||||
};
|
||||
|
||||
export const IonTabs = /*@__PURE__*/ (() =>
|
||||
class extends React.Component<Props> {
|
||||
context!: React.ContextType<typeof NavContext>;
|
||||
/**
|
||||
* `routerOutletRef` allows users to add a `ref` to `IonRouterOutlet`.
|
||||
* Without this, `ref.current` will be `undefined` in the user's app,
|
||||
* breaking their ability to access the `IonRouterOutlet` instance.
|
||||
* Do not remove this ref.
|
||||
*/
|
||||
routerOutletRef: React.Ref<HTMLIonRouterOutletElement> = React.createRef();
|
||||
selectTabHandler?: (tag: string) => boolean;
|
||||
tabBarRef = React.createRef<any>();
|
||||
@@ -72,6 +58,14 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
ionTabContextState: IonTabsContextState = {
|
||||
activeTab: undefined,
|
||||
selectTab: () => false,
|
||||
hasRouterOutlet: false,
|
||||
/**
|
||||
* Tab bar can be used as a standalone component,
|
||||
* so the props can not be passed directly to the
|
||||
* tab bar component. Instead, props will be
|
||||
* passed through the context.
|
||||
*/
|
||||
tabBarProps: { ref: this.tabBarRef },
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
@@ -90,9 +84,32 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
}
|
||||
}
|
||||
|
||||
renderTabsInner(children: React.ReactNode, outlet: React.ReactElement<{}> | undefined) {
|
||||
return (
|
||||
<IonTabsInner {...this.props}>
|
||||
{React.Children.map(children, (child: React.ReactNode) => {
|
||||
if (React.isValidElement(child)) {
|
||||
const isRouterOutlet =
|
||||
child.type === IonRouterOutlet ||
|
||||
(child.type as any).isRouterOutlet ||
|
||||
(child.type === Fragment && child.props.children[0].type === IonRouterOutlet);
|
||||
|
||||
if (isRouterOutlet) {
|
||||
/**
|
||||
* The modified outlet needs to be returned to include
|
||||
* the ref.
|
||||
*/
|
||||
return outlet;
|
||||
}
|
||||
}
|
||||
return child;
|
||||
})}
|
||||
</IonTabsInner>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let outlet: React.ReactElement<{}> | undefined;
|
||||
let tabBar: React.ReactElement | undefined;
|
||||
// Check if IonTabs has any IonTab children
|
||||
let hasTab = false;
|
||||
const { className, onIonTabsDidChange, onIonTabsWillChange, ...props } = this.props;
|
||||
@@ -102,19 +119,15 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
? (this.props.children as ChildFunction)(this.ionTabContextState)
|
||||
: this.props.children;
|
||||
|
||||
const outletProps = {
|
||||
ref: this.routerOutletRef,
|
||||
};
|
||||
|
||||
React.Children.forEach(children, (child: any) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) {
|
||||
return;
|
||||
}
|
||||
if (child.type === IonRouterOutlet || child.type.isRouterOutlet) {
|
||||
outlet = React.cloneElement(child, outletProps);
|
||||
outlet = React.cloneElement(child);
|
||||
} else if (child.type === Fragment && child.props.children[0].type === IonRouterOutlet) {
|
||||
outlet = React.cloneElement(child.props.children[0], outletProps);
|
||||
outlet = React.cloneElement(child.props.children[0]);
|
||||
} else if (child.type === IonTab) {
|
||||
/**
|
||||
* This indicates that IonTabs will be using a basic tab-based navigation
|
||||
@@ -123,9 +136,10 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
hasTab = true;
|
||||
}
|
||||
|
||||
this.ionTabContextState.hasRouterOutlet = !!outlet;
|
||||
|
||||
let childProps: any = {
|
||||
ref: this.tabBarRef,
|
||||
routerOutletRef: this.routerOutletRef,
|
||||
...this.ionTabContextState.tabBarProps,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -149,14 +163,7 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
};
|
||||
}
|
||||
|
||||
if (child.type === IonTabBar || child.type.isTabBar) {
|
||||
tabBar = React.cloneElement(child, childProps);
|
||||
} else if (
|
||||
child.type === Fragment &&
|
||||
(child.props.children[1].type === IonTabBar || child.props.children[1].type.isTabBar)
|
||||
) {
|
||||
tabBar = React.cloneElement(child.props.children[1], childProps);
|
||||
}
|
||||
this.ionTabContextState.tabBarProps = childProps;
|
||||
});
|
||||
|
||||
if (!outlet && !hasTab) {
|
||||
@@ -186,46 +193,10 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
<IonTabsContext.Provider value={this.ionTabContextState}>
|
||||
{this.context.hasIonicRouter() ? (
|
||||
<PageManager className={className ? `${className}` : ''} routeInfo={this.context.routeInfo} {...props}>
|
||||
<IonTabsInner {...this.props}>
|
||||
{React.Children.map(children, (child: React.ReactNode) => {
|
||||
if (React.isValidElement(child)) {
|
||||
const isTabBar =
|
||||
child.type === IonTabBar ||
|
||||
(child.type as any).isTabBar ||
|
||||
(child.type === Fragment &&
|
||||
(child.props.children[1].type === IonTabBar || child.props.children[1].type.isTabBar));
|
||||
const isRouterOutlet =
|
||||
child.type === IonRouterOutlet ||
|
||||
(child.type as any).isRouterOutlet ||
|
||||
(child.type === Fragment && child.props.children[0].type === IonRouterOutlet);
|
||||
|
||||
if (isTabBar) {
|
||||
/**
|
||||
* The modified tabBar needs to be returned to include
|
||||
* the context and the overridden methods.
|
||||
*/
|
||||
return tabBar;
|
||||
}
|
||||
if (isRouterOutlet) {
|
||||
/**
|
||||
* The modified outlet needs to be returned to include
|
||||
* the ref.
|
||||
*/
|
||||
return outlet;
|
||||
}
|
||||
}
|
||||
return child;
|
||||
})}
|
||||
</IonTabsInner>
|
||||
{this.renderTabsInner(children, outlet)}
|
||||
</PageManager>
|
||||
) : (
|
||||
<div className={className ? `${className}` : 'ion-tabs'} {...props} style={hostStyles}>
|
||||
{tabBar?.props.slot === 'top' ? tabBar : null}
|
||||
<div style={tabsInner} className="tabs-inner">
|
||||
{outlet}
|
||||
</div>
|
||||
{tabBar?.props.slot === 'bottom' ? tabBar : null}
|
||||
</div>
|
||||
this.renderTabsInner(children, outlet)
|
||||
)}
|
||||
</IonTabsContext.Provider>
|
||||
);
|
||||
|
||||
@@ -3,9 +3,25 @@ import React from 'react';
|
||||
export interface IonTabsContextState {
|
||||
activeTab: string | undefined;
|
||||
selectTab: (tab: string) => boolean;
|
||||
hasRouterOutlet: boolean;
|
||||
tabBarProps: TabBarProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab bar can be used as a standalone component,
|
||||
* so the props can not be passed directly to the
|
||||
* tab bar component. Instead, props will be
|
||||
* passed through the context.
|
||||
*/
|
||||
type TabBarProps = {
|
||||
ref: React.RefObject<any>;
|
||||
onIonTabsWillChange?: (e: CustomEvent) => void;
|
||||
onIonTabsDidChange?: (e: CustomEvent) => void;
|
||||
};
|
||||
|
||||
export const IonTabsContext = React.createContext<IonTabsContextState>({
|
||||
activeTab: undefined,
|
||||
selectTab: () => false,
|
||||
hasRouterOutlet: false,
|
||||
tabBarProps: { ref: React.createRef() },
|
||||
});
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
34
packages/vue-router/package-lock.json
generated
34
packages/vue-router/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^8.3.1"
|
||||
"@ionic/vue": "^8.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
@@ -661,9 +661,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -852,11 +852,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/vue": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.3.1.tgz",
|
||||
"integrity": "sha512-UWOVuibeHY4xjWl2Sh93FYiXLBZgAVXoh8ObskV93plm36iS611gpHqw47lBeR29uHwZAohfQVT0WLN6GWQ3JQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.3.3.tgz",
|
||||
"integrity": "sha512-6EAPWdmQDvazP4ZsCRjWlG91Kx+1vYxX1gHx02Xvcc7Dn8hRrMW58IAAQ0BqSYsrHNFTKVtwD3cJbmnut8Ghyg==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "8.3.1",
|
||||
"@ionic/core": "8.3.3",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
},
|
||||
@@ -7878,9 +7878,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -7993,11 +7993,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/vue": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.3.1.tgz",
|
||||
"integrity": "sha512-UWOVuibeHY4xjWl2Sh93FYiXLBZgAVXoh8ObskV93plm36iS611gpHqw47lBeR29uHwZAohfQVT0WLN6GWQ3JQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.3.3.tgz",
|
||||
"integrity": "sha512-6EAPWdmQDvazP4ZsCRjWlG91Kx+1vYxX1gHx02Xvcc7Dn8hRrMW58IAAQ0BqSYsrHNFTKVtwD3cJbmnut8Ghyg==",
|
||||
"requires": {
|
||||
"@ionic/core": "8.3.1",
|
||||
"@ionic/core": "8.3.3",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "Vue Router integration for @ionic/vue",
|
||||
"scripts": {
|
||||
"test.spec": "jest",
|
||||
@@ -44,7 +44,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/ionic-team/ionic-framework#readme",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^8.3.1"
|
||||
"@ionic/vue": "^8.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.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.
|
||||
|
||||
## [8.3.3](https://github.com/ionic-team/ionic-framework/compare/v8.3.2...v8.3.3) (2024-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tabs, tab-bar:** use standalone tab bar in Vue, React ([#29940](https://github.com/ionic-team/ionic-framework/issues/29940)) ([b7b383b](https://github.com/ionic-team/ionic-framework/commit/b7b383bee080b72de2e6307ff9a9a051314c69ed)), closes [#29885](https://github.com/ionic-team/ionic-framework/issues/29885) [#29924](https://github.com/ionic-team/ionic-framework/issues/29924)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.2](https://github.com/ionic-team/ionic-framework/compare/v8.3.1...v8.3.2) (2024-10-02)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.3.1](https://github.com/ionic-team/ionic-framework/compare/v8.3.0...v8.3.1) (2024-09-17)
|
||||
|
||||
|
||||
|
||||
18
packages/vue/package-lock.json
generated
18
packages/vue/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1",
|
||||
"@ionic/core": "^8.3.3",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -208,9 +208,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
@@ -3970,9 +3970,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.1.tgz",
|
||||
"integrity": "sha512-md4JFwKYLgN/YP+uzoTE5H7ah0W5SQQNZ1cJOQtxhv0ytCCHHaXJrfRVzefdy8iy8NdzL9s6EV5ZTKYH98E+ZQ==",
|
||||
"version": "8.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.3.tgz",
|
||||
"integrity": "sha512-f2PXV0jFIFPdjP+NbmQ1mXqRQ4KWi0U0jdQd3wDYsJFWQLmWXhW7Yp/4lCDdl0ouMeZRB2phddqFct1c7H6PyA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.20.0",
|
||||
"ionicons": "^7.2.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "8.3.1",
|
||||
"version": "8.3.3",
|
||||
"description": "Vue specific wrapper for @ionic/core",
|
||||
"scripts": {
|
||||
"eslint": "eslint src",
|
||||
@@ -66,7 +66,7 @@
|
||||
"vue-router": "^4.0.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.3.1",
|
||||
"@ionic/core": "^8.3.3",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
"vetur": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineCustomElement } from "@ionic/core/components/ion-tab-bar.js";
|
||||
import type { VNode } from "vue";
|
||||
import type { VNode, Ref } from "vue";
|
||||
import { h, defineComponent, getCurrentInstance, inject } from "vue";
|
||||
|
||||
// TODO(FW-2969): types
|
||||
@@ -16,6 +16,12 @@ interface Tab {
|
||||
ref: VNode;
|
||||
}
|
||||
|
||||
interface TabBarData {
|
||||
hasRouterOutlet: boolean;
|
||||
_tabsWillChange: Function;
|
||||
_tabsDidChange: Function;
|
||||
}
|
||||
|
||||
const isTabButton = (child: any) => child.type?.name === "IonTabButton";
|
||||
|
||||
const getTabs = (nodes: VNode[]) => {
|
||||
@@ -34,20 +40,23 @@ const getTabs = (nodes: VNode[]) => {
|
||||
|
||||
export const IonTabBar = defineComponent({
|
||||
name: "IonTabBar",
|
||||
props: {
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
_tabsWillChange: { type: Function, default: () => {} },
|
||||
_tabsDidChange: { type: Function, default: () => {} },
|
||||
_hasRouterOutlet: { type: Boolean, default: false },
|
||||
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabState: {
|
||||
activeTab: undefined,
|
||||
tabs: {},
|
||||
/**
|
||||
* Passing this prop to each tab button
|
||||
* lets it be aware of the presence of
|
||||
* the router outlet.
|
||||
*/
|
||||
hasRouterOutlet: false,
|
||||
},
|
||||
tabVnodes: [],
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
_tabsWillChange: { type: Function, default: () => {} },
|
||||
_tabsDidChange: { type: Function, default: () => {} },
|
||||
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||
};
|
||||
},
|
||||
updated() {
|
||||
@@ -55,7 +64,7 @@ export const IonTabBar = defineComponent({
|
||||
},
|
||||
methods: {
|
||||
setupTabState(ionRouter: any) {
|
||||
const hasRouterOutlet = this.$props._hasRouterOutlet;
|
||||
const hasRouterOutlet = this.$data.tabState.hasRouterOutlet;
|
||||
/**
|
||||
* For each tab, we need to keep track of its
|
||||
* base href as well as any child page that
|
||||
@@ -75,13 +84,6 @@ export const IonTabBar = defineComponent({
|
||||
ref: child,
|
||||
};
|
||||
|
||||
/**
|
||||
* Passing this prop to each tab button
|
||||
* lets it be aware of the presence of
|
||||
* the router outlet.
|
||||
*/
|
||||
tabState.hasRouterOutlet = hasRouterOutlet;
|
||||
|
||||
/**
|
||||
* Passing this prop to each tab button
|
||||
* lets it be aware of the state that
|
||||
@@ -126,7 +128,7 @@ export const IonTabBar = defineComponent({
|
||||
* @param ionRouter
|
||||
*/
|
||||
checkActiveTab(ionRouter: any) {
|
||||
const hasRouterOutlet = this.$props._hasRouterOutlet;
|
||||
const hasRouterOutlet = this.$data.tabState.hasRouterOutlet;
|
||||
const currentRoute = ionRouter?.getCurrentRouteInfo();
|
||||
const childNodes = this.$data.tabVnodes;
|
||||
const { tabs, activeTab: prevActiveTab } = this.$data.tabState;
|
||||
@@ -216,7 +218,7 @@ export const IonTabBar = defineComponent({
|
||||
this.tabSwitch(activeTab);
|
||||
},
|
||||
tabSwitch(activeTab: string, ionRouter?: any) {
|
||||
const hasRouterOutlet = this.$props._hasRouterOutlet;
|
||||
const hasRouterOutlet = this.$data.tabState.hasRouterOutlet;
|
||||
const childNodes = this.$data.tabVnodes;
|
||||
const { activeTab: prevActiveTab } = this.$data.tabState;
|
||||
const tabState = this.$data.tabState;
|
||||
@@ -227,7 +229,7 @@ export const IonTabBar = defineComponent({
|
||||
const tabDidChange = activeTab !== prevActiveTab;
|
||||
if (tabBar) {
|
||||
if (activeChild) {
|
||||
tabDidChange && this.$props._tabsWillChange(activeTab);
|
||||
tabDidChange && this.$data._tabsWillChange(activeTab);
|
||||
|
||||
if (hasRouterOutlet && ionRouter !== null) {
|
||||
ionRouter.handleSetCurrentTab(activeTab);
|
||||
@@ -235,7 +237,7 @@ export const IonTabBar = defineComponent({
|
||||
|
||||
tabBar.selectedTab = tabState.activeTab = activeTab;
|
||||
|
||||
tabDidChange && this.$props._tabsDidChange(activeTab);
|
||||
tabDidChange && this.$data._tabsDidChange(activeTab);
|
||||
} else {
|
||||
/**
|
||||
* When going to a tab that does
|
||||
@@ -250,6 +252,17 @@ export const IonTabBar = defineComponent({
|
||||
},
|
||||
mounted() {
|
||||
const ionRouter: any = inject("navManager", null);
|
||||
/**
|
||||
* Tab bar can be used as a standalone component,
|
||||
* so it cannot be modified directly through
|
||||
* IonTabs. Instead, data will be passed through
|
||||
* the provide/inject.
|
||||
*/
|
||||
const tabBarData = inject<Ref<TabBarData>>("tabBarData");
|
||||
|
||||
this.$data.tabState.hasRouterOutlet = tabBarData.value.hasRouterOutlet;
|
||||
this.$data._tabsWillChange = tabBarData.value._tabsWillChange;
|
||||
this.$data._tabsDidChange = tabBarData.value._tabsDidChange;
|
||||
|
||||
this.setupTabState(ionRouter);
|
||||
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { defineCustomElement } from "@ionic/core/components/ion-tabs.js";
|
||||
import type { VNode } from "vue";
|
||||
import { h, defineComponent, Fragment, isVNode } from "vue";
|
||||
import {
|
||||
h,
|
||||
defineComponent,
|
||||
Fragment,
|
||||
isVNode,
|
||||
provide,
|
||||
shallowRef,
|
||||
} from "vue";
|
||||
|
||||
import { IonTab } from "../proxies";
|
||||
|
||||
@@ -9,6 +16,12 @@ const DID_CHANGE = "ionTabsDidChange";
|
||||
|
||||
// TODO(FW-2969): types
|
||||
|
||||
interface TabBarData {
|
||||
hasRouterOutlet: boolean;
|
||||
_tabsWillChange: Function;
|
||||
_tabsDidChange: Function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vue 3.2.38 fixed an issue where Web Component
|
||||
* names are respected using kebab case instead of pascal case.
|
||||
@@ -24,13 +37,6 @@ const isRouterOutlet = (node: VNode) => {
|
||||
);
|
||||
};
|
||||
|
||||
const isTabBar = (node: VNode) => {
|
||||
return (
|
||||
node.type &&
|
||||
((node.type as any).name === "IonTabBar" || node.type === "ion-tab-bar")
|
||||
);
|
||||
};
|
||||
|
||||
const isTab = (node: VNode): boolean => {
|
||||
// The `ion-tab` component was created with the `v-for` directive.
|
||||
if (node.type === Fragment) {
|
||||
@@ -49,7 +55,43 @@ const isTab = (node: VNode): boolean => {
|
||||
export const IonTabs = /*@__PURE__*/ defineComponent({
|
||||
name: "IonTabs",
|
||||
emits: [WILL_CHANGE, DID_CHANGE],
|
||||
data() {
|
||||
return {
|
||||
hasRouterOutlet: false,
|
||||
};
|
||||
},
|
||||
setup(props, { slots, emit }) {
|
||||
const slottedContent: VNode[] | undefined =
|
||||
slots.default && slots.default();
|
||||
let routerOutlet: VNode | undefined = undefined;
|
||||
|
||||
if (slottedContent && slottedContent.length > 0) {
|
||||
/**
|
||||
* Developers must pass an ion-router-outlet
|
||||
* inside of ion-tabs if they want to use
|
||||
* the history stack or URL updates associated
|
||||
* with the router.
|
||||
*/
|
||||
routerOutlet = slottedContent.find((child: VNode) =>
|
||||
isRouterOutlet(child)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab bar can be used as a standalone component,
|
||||
* so it cannot be modified directly through
|
||||
* IonTabs. Instead, data will be passed through
|
||||
* the provide/inject.
|
||||
*/
|
||||
provide(
|
||||
"tabBarData",
|
||||
shallowRef<TabBarData>({
|
||||
hasRouterOutlet: !!routerOutlet,
|
||||
_tabsWillChange: (tab: string) => emit(WILL_CHANGE, { tab }),
|
||||
_tabsDidChange: (tab: string) => emit(DID_CHANGE, { tab }),
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
props,
|
||||
slots,
|
||||
@@ -68,9 +110,10 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
|
||||
defineCustomElement();
|
||||
},
|
||||
render() {
|
||||
const { slots, emit, props } = this;
|
||||
const slottedContent = slots.default && slots.default();
|
||||
let routerOutlet;
|
||||
const { slots, props } = this;
|
||||
const slottedContent: VNode[] | undefined =
|
||||
slots.default && slots.default();
|
||||
let routerOutlet: VNode | undefined = undefined;
|
||||
let hasTab = false;
|
||||
|
||||
if (slottedContent && slottedContent.length > 0) {
|
||||
@@ -78,7 +121,7 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
|
||||
* Developers must pass an ion-router-outlet
|
||||
* inside of ion-tabs if they want to use
|
||||
* the history stack or URL updates associated
|
||||
* wit the router.
|
||||
* with the router.
|
||||
*/
|
||||
routerOutlet = slottedContent.find((child: VNode) =>
|
||||
isRouterOutlet(child)
|
||||
@@ -103,30 +146,6 @@ export const IonTabs = /*@__PURE__*/ defineComponent({
|
||||
);
|
||||
}
|
||||
|
||||
if (slottedContent && slottedContent.length > 0) {
|
||||
const slottedTabBar = slottedContent.find((child: VNode) =>
|
||||
isTabBar(child)
|
||||
);
|
||||
|
||||
if (slottedTabBar) {
|
||||
if (!slottedTabBar.props) {
|
||||
slottedTabBar.props = {};
|
||||
}
|
||||
/**
|
||||
* ionTabsWillChange and ionTabsDidChange are
|
||||
* fired from `ion-tabs`, so we need to pass these down
|
||||
* as props so they can fire when the active tab changes.
|
||||
* TODO: We may want to move logic from the tab bar into here
|
||||
* so we do not have code split across two components.
|
||||
*/
|
||||
slottedTabBar.props._tabsWillChange = (tab: string) =>
|
||||
emit(WILL_CHANGE, { tab });
|
||||
slottedTabBar.props._tabsDidChange = (tab: string) =>
|
||||
emit(DID_CHANGE, { tab });
|
||||
slottedTabBar.props._hasRouterOutlet = !!routerOutlet;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTab) {
|
||||
return h(
|
||||
"ion-tabs",
|
||||
|
||||
Reference in New Issue
Block a user