Issue number: resolves#28337
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
Duplicate instances of `menuController` are being created in
`@ionic/angular`. `ion-menu` registers itself in the `menuController`
from `@ionic/core`, but the `MenuController` from `@ionic/angular` uses
the `menuController` from `@ionic/core/components`. This is how the
overlay providers work too. Normally, this is not a problem. However,
`menuController` caches references to registered menus in each
controller instances:
dcbf45101f/core/src/utils/menu-controller/index.ts (L14)
This means that since there are two different controllers,
`menuController` B does not know about the menus in `menuController` A.
The end result is that the menu controller used in developer
applications did not have references to the registered menus, which gave
the impression that the menu controller did not work.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Updated the architecture of `MenuController` in Ionic Angular to
accept a `menuController` instance. This allows `@ionic/angular` to pass
the `menuController` from `@ionic/core` and for
`@ionic/angular/standalone` to pass the `menuController` from
`@ionic/core/components`.
Note: Overlay controllers don't **need** this change per-se since they
don't cache references to overlays internally (they just query the DOM).
However, I think it would be good to have a consistent architecture
here, so I'll put up a separate PR that makes this change for overlays
too.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
Dev build: `7.5.1-dev.11697123035.1ee6b4a2`
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Issue number: Resolves#28186
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
Ionic lifecycle hooks do not execute a cleanup function when the
underlying `useEffect` is unmounted.
```ts
useEffect(() => {
return () => {
console.log('cleanup'); // called
};
});
useIonViewWillEnter(() => {
return () => {
console.log('cleanup'); // never called
};
});
```
Ionic's implementation registers the lifecycle callback to be handled at
a later time, by the page managers. However, it does not keep a
reference to the returned callback, so it cannot execute it when the
`useEffect` is unmounted.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Ionic lifecycle hooks execute dev-specified cleanup functions
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Dev-build: `7.4.4-dev.11696956070.1faa3cfe`
This PR builds on the changes in #28316.
---------
Co-authored-by: Maria Hutt <maria@ionic.io>
Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com>
Issue number: N/A
Resolves feedback identified here:
baa37ef1e3 (r1356414362)
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
The lifecycle interfaces are not exported from
`@ionic/angular/standalone`.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Lifecycle interfaces are exported from `@ionic/angular/standalone`.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
While debugging #28186, Maria and I identified that Ionic's lifecycle
event listeners (`ionViewWillEnter`, etc.) were being registered
multiple times on the same `.ion-page` element. This resulted in
problematic behavior, where a user's implementation of our lifecycle
hooks, would execute their callback multiple times.
```ts
useIonViewWillEnter(() => {
// This is called 2x for every time the `ionViewWillEnter` event is emitted (in React 18, dev mode)
console.log('hello world');
});
```
When the Ionic lifecycle event listeners are registered in React, we
bind the scope of the class to the callback function. When removing the
event listener we additional use the `.bind` syntax.
```tsx
componentDidMount() {
element.addEventListener('ionViewWillEnter', this.ionViewWillEnter.bind(this));
}
componentWillUnmount() {
// This creates a new instance of the function to remove! It doesn't remove the original event listener.
element.removeEventListener('ionViewWillEnter', this.ionViewWillEnter.bind(this));
}
```
The `.bind` method returns a new instance of the function. This means in
the implementation we are creating a new instance of the function when
both adding and removing the event listener - resulting in the
`removeEventListener` to never remove the original event listener.
This behavior only occurred in React 18 in dev mode, as a result of the
mount/unmount behavior running 2x for `useEffect` hooks.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Ionic lifecycle event listeners are removed from element references
when they are unmounted.
- User's lifecycle callback methods are only invoked once per event
emission.
|Before|After|
|----|----|
|<img alt="CleanShot 2023-10-09 at 18 32 08@2x"
src="https://github.com/ionic-team/ionic-framework/assets/13732623/53f2ef5d-5900-4a84-b427-fa6c9d35d081">|<img
alt="CleanShot 2023-10-09 at 18 29 37@2x"
src="https://github.com/ionic-team/ionic-framework/assets/13732623/c8a9a657-a0bf-4d6d-9f21-a41a686de490">|
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
---------
Co-authored-by: Maria Hutt <maria@ionic.io>
Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com>
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
**1. Bundle Size Reductions**
All Ionic UI components and Ionicons are added to the final bundle of an
Ionic Angular application. This is because all components and icons are
lazily loaded as needed. This prevents the compiler from properly tree
shaking applications. This does not cause all components and icons to be
loaded on application start, but it does increase the size of the final
app output that all users need to download.
**Related Issues**
https://github.com/ionic-team/ionicons/issues/910https://github.com/ionic-team/ionicons/issues/536https://github.com/ionic-team/ionic-framework/issues/27280https://github.com/ionic-team/ionic-framework/issues/24352
**2. Standalone Component Support**
Standalone Components are a stable API as of Angular 15. The Ionic
starter apps on the CLI have NgModule and Standalone options, but all of
the Ionic components are still lazily/dynamically loaded using
`IonicModule`. Standalone components in Ionic also enable support for
new Angular features such as bundling with ESBuild instead of Webpack.
ESBuild does not work in Ionic Angular right now because components
cannot be statically analyzed since they are dynamically imported.
We added preliminary support for standalone components in Ionic v6.3.0.
This enabled developers to use their own custom standalone components
when routing with `ion-router-outlet`. However, we did not ship
standalone components for Ionic's UI components.
**Related Issues**
https://github.com/ionic-team/ionic-framework/issues/25404https://github.com/ionic-team/ionic-framework/issues/27251https://github.com/ionic-team/ionic-framework/issues/27387
**3. Faster Component Load Times**
Since Ionic Angular components are lazily loaded, they also need to be
hydrated. However, this hydration does not happen immediately which
prevents components from being usable for multiple frames.
**Related Issues**
https://github.com/ionic-team/ionic-framework/issues/24352https://github.com/ionic-team/ionic-framework/issues/26474
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Ionic components and directives are accessible as Angular standalone
components/directives
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Associated documentation branch:
https://github.com/ionic-team/ionic-docs/tree/feature-7.5
---------
Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
Co-authored-by: Sean Perkins <sean@ionic.io>
Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com>
Co-authored-by: Maria Hutt <maria@ionic.io>
Co-authored-by: Sean Perkins <13732623+sean-perkins@users.noreply.github.com>
Issue number: resolves#27911
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
The `openURL` utility is not available to developers.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Export `openURL` utilities from `@ionic/core`, `@ionic/angular`,
`@ionic/react` and `@ionic/vue`.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Issue number: resolves#17499
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
Currently, there isn't a way to position toasts such that they don't
overlap navigation elements such as headers, footers, and FABs.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
Added the new `positionAnchor` property, which specifies an element that
the toast's position should be anchored to.
While the name can be tweaked, we should take care to keep the relation
between it and the `position` property clear. The `position` acts as a
sort of "origin" point, and the toast is moved from there to sit near
the chosen anchor element. This is important because it helps clarify
why the toast sits above the anchor for `position="bottom"` and vice
versa.
I chose not to rename the `position` prop itself to avoid breaking
changes.
Docs PR: https://github.com/ionic-team/ionic-docs/pull/3158
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
---------
Co-authored-by: ionitron <hi@ionicframework.com>
Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
CI is failing for Cypress apps due to
https://github.com/cypress-io/cypress/issues/27804#issuecomment-1721476731.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- All Cypress test apps have been updated to Cypress 13.2.0 which is not
affected by this issue.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Issue number: Resolves#27798
---------
## What is the current behavior
React IonNav component's views are missing keys, leading to unnecessary
duplicate mounting of components.
## What is the new behavior?
- Adds key to views of React IonNav component.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
---------
Co-authored-by: Sean Perkins <sean@ionic.io>
Issue number: resolves#28165
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
The overlay implementation in Vue only checks for truthy
`keepContentsMounted` values. When setting this prop as an attribute,
the value of it is `''` which is falsy. As a result, content does not
get mounted.
One of Vue's ESLint rules states that this should be supported:
https://eslint.vuejs.org/rules/prefer-true-attribute-shorthand.html
Part of the issue may also be that Vue does not know the type of this
property and so it assume "any":
> The shorthand form is not always equivalent! If a prop accepts
multiple types, but Boolean is not the first one, a shorthand prop won't
pass true.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- The overlay wrapper now checks for `''` values. If
`keepContentsMounted === ''` then the inner contents will be mounted
because this means the prop is being set using the attribute shorthand.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Dev build: `7.3.5-dev.11694621267.1e5f63c2`
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
The instructions doesn't provide clear directory paths for syncing local
changes.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- The instructions has clear directory paths for syncing local changes.
- Updated out of date information.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
N/A
Issue number: resolves#28102
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
When one modal is added and another modal is removed, the modal that is
removed does not account for the newly added modal when updating the
overlay context in React. As a result, the inner contents of the newly
added modal is not mounted.
We originally tried to fix this in
https://github.com/ionic-team/ionic-framework/pull/24553, but the fix
was not complete. While storing the latest information in a React ref
was correct, the way we updated the ref was done in a way such that data
was still stale.
In particular, the `overlaysRef` is updated whenever `IonOverlayManager`
is re-rendered. State updates are batched, so updating the state twice
in quick succession does not necessarily result in 2 separate renders.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- We need to make sure the ref is updated synchronously before any
render so that `addOverlay` and `removeOverlay` always have access to
the latest data.
- Added a test
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Dev build: `7.3.3-dev.11693592339.18e000af`
---------
Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com>
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
- The instructions doesn't provide clear directory paths for syncing
local changes.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- The instructions has clear directory paths for syncing local changes.
- Switched to the `[!NOTE]` for notes.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
N/A
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
The Vue Router implementation [assigns data to the `routerAnimation` on
the view
item](cddefd1548/packages/vue/src/components/IonRouterOutlet.ts (L165-L170)),
but the [type does not exist on the `ViewItem`
interface](https://github.com/ionic-team/ionic-framework/blob/main/packages/vue-router/src/types.ts#L62-L76).
The actual routing implementation does not make use of the type, but
this is backfilling the information when we wire up the types to the
implementation.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Adds the missing type for `routerAnimation` to the `ViewItem`
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Issue number: Resolves#28010
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
`onDidDismiss` and `onWillPresent` will fire twice when having a manual
binding in your implementation for inline overlays.
e.g.:
```tsx
<IonAlert onDidDismiss={() => console.log('hello world')} />
```
Will result in:
> hello world
> hello world
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- `onDidDismiss` and `onWillPresent` do not execute the callback handler
twice per invocation
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Dev-build: `7.3.1-dev.11692305436.16a4008f`
Issue number: Resolves#23480
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
Angular's min/max validators do not work with `ion-input[type=number]`.
Using the built-in validators with `ion-input` will not update the
control status to invalid, reflect the `ng-invalid` class or report the
correct errors.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- The `IonicModule` now includes two additional directive declarations
that extend Angular's built-in min/max validators and target the
`ion-input` component when using `type="number"`.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Issue number: Resolves#27212
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
`ionTabsWillChange` emits _after_ the tab view is activated in the
stack.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- `ionTabsWillChange` emits _before_ the tab view is activated in the
stack.
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
Dev-build: `7.2.4-dev.11692040948.1fd0ecd2`
Issue number: N/A
---------
<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->
<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->
The sync script for the React package is out of date. It will
unintentionally delete the symlink directory of the build output from
`core/`, which breaks the build for the package during local
development.
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
- Updates the sync script to package and install the `core` package
- Matches the implementation pattern used for the sync script in our
other packages
## Does this introduce a breaking change?
- [ ] Yes
- [x] No
<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->