diff --git a/CHANGELOG.md b/CHANGELOG.md index d02f474078..8ded73d9ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [5.6.14](https://github.com/ionic-team/ionic/compare/v5.6.13...v5.6.14) (2021-08-18) + + +### Bug Fixes + +* **back-button:** MD ripple now accounts for --ripple-color ([#23749](https://github.com/ionic-team/ionic/issues/23749)) ([6b18a89](https://github.com/ionic-team/ionic/commit/6b18a89ac2c446082ce7faebe329157eedb13a0e)), closes [#23748](https://github.com/ionic-team/ionic/issues/23748) +* **img:** correctly determine when to load image when scrolling quickly on slower devices ([#23704](https://github.com/ionic-team/ionic/issues/23704)) ([067e621](https://github.com/ionic-team/ionic/commit/067e621bbc3865184ae114b8c91122188c13c860)), closes [#23703](https://github.com/ionic-team/ionic/issues/23703) +* **item-sliding:** prevent scrolling during slide gesture ([#23774](https://github.com/ionic-team/ionic/issues/23774)) ([e0c4ad3](https://github.com/ionic-team/ionic/commit/e0c4ad30bec3f2bd325d65b210ffb0437149810f)), closes [#19564](https://github.com/ionic-team/ionic/issues/19564) +* **nav:** custom animation is now used correctly ([#23779](https://github.com/ionic-team/ionic/issues/23779)) ([f9415ef](https://github.com/ionic-team/ionic/commit/f9415ef8a689e26078bdd01623348c79f9f818ad)), closes [#23777](https://github.com/ionic-team/ionic/issues/23777) +* **vue:** using router.go now shows correct view ([#23773](https://github.com/ionic-team/ionic/issues/23773)) ([621f4fa](https://github.com/ionic-team/ionic/commit/621f4faa1ab03137158127a56c7fe0aa1f7ae489)), closes [#22563](https://github.com/ionic-team/ionic/issues/22563) + + + # [6.0.0-beta.3](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.2...v6.0.0-beta.3) (2021-08-04) @@ -14,120 +27,6 @@ -# [6.0.0-beta.2](https://github.com/ionic-team/ionic/compare/v5.6.12...v6.0.0-beta.2) (2021-07-21) - - -### Bug Fixes - -* **accordion:** value can now be set as string when using multiple is true ([#23581](https://github.com/ionic-team/ionic/issues/23581)) ([8f172de](https://github.com/ionic-team/ionic/commit/8f172de355bc7c910d600ce4d8446b04a6212545)), closes [#23550](https://github.com/ionic-team/ionic/issues/23550) -* **angular:** modal and popover now have correct props defined on angular component ([#23565](https://github.com/ionic-team/ionic/issues/23565)) ([e5a7b34](https://github.com/ionic-team/ionic/commit/e5a7b342623b159d41cc83e0a418fb3984ceb3a7)) -* **datetime:** add keyboard year navigation ([#23585](https://github.com/ionic-team/ionic/issues/23585)) ([55bd1f7](https://github.com/ionic-team/ionic/commit/55bd1f749bac01cc691e16283728c42e755cc706)), closes [#21553](https://github.com/ionic-team/ionic/issues/21553) [#18122](https://github.com/ionic-team/ionic/issues/18122) -* **datetime:** selecting time now works correctly on firefox ([#23583](https://github.com/ionic-team/ionic/issues/23583)) ([4188964](https://github.com/ionic-team/ionic/commit/4188964dc8da2c46494245b81864ca6e305611f5)), closes [#23545](https://github.com/ionic-team/ionic/issues/23545) -* **datetime:** years displayed now more consistent with v5 datetime, max and min are now accounted for in MD mode ([#23616](https://github.com/ionic-team/ionic/issues/23616)) ([be219a2](https://github.com/ionic-team/ionic/commit/be219a2814800927e6328ff105616713003340b7)), closes [#23615](https://github.com/ionic-team/ionic/issues/23615) - - -### Features - -* **breadcrumbs:** ionCollapsedClick event payload now contains references to collapsed breadcrumb elements ([#23611](https://github.com/ionic-team/ionic/issues/23611)) ([9ce57d2](https://github.com/ionic-team/ionic/commit/9ce57d2efb84130895a37e22e0fd7e5d713a9fa5)), closes [#23552](https://github.com/ionic-team/ionic/issues/23552) -* **datetime:** add showDefaultTimeLabel property and time-label slot ([#23577](https://github.com/ionic-team/ionic/issues/23577)) ([7ac0109](https://github.com/ionic-team/ionic/commit/7ac010943b2c9ad42a1833153ea16ccffd169b91)), closes [#23555](https://github.com/ionic-team/ionic/issues/23555) -* **datetime:** add size property ([#23649](https://github.com/ionic-team/ionic/issues/23649)) ([321341d](https://github.com/ionic-team/ionic/commit/321341d97dff98b76b69a1efce58923a80e92bc4)), closes [#23518](https://github.com/ionic-team/ionic/issues/23518) -* **range:** add support for customizing pin format ([#22972](https://github.com/ionic-team/ionic/issues/22972)) ([8f2c4f7](https://github.com/ionic-team/ionic/commit/8f2c4f73db167503cdf60222f42bcaadf905b401)) -* **segment:** add keyboard navigation, add selectOnFocus property to control selection follow focus behavior ([#23590](https://github.com/ionic-team/ionic/issues/23590)) ([b6c53e5](https://github.com/ionic-team/ionic/commit/b6c53e539b0855fa95b0fe02e5fa74ce403b68b8)), closes [#23520](https://github.com/ionic-team/ionic/issues/23520) -* **select:** update popover interface to match MD spec on desktop, allow multiple values in popover interface ([#23474](https://github.com/ionic-team/ionic/issues/23474)) ([2c07a15](https://github.com/ionic-team/ionic/commit/2c07a1566b6f8570f7e12a55ca8f86d8fb8a968e)), closes [#23657](https://github.com/ionic-team/ionic/issues/23657) [#15500](https://github.com/ionic-team/ionic/issues/15500) [#12310](https://github.com/ionic-team/ionic/issues/12310) - - -### Performance Improvements - -* remove shims for legacy browsers no longer supported in v6 ([#23592](https://github.com/ionic-team/ionic/issues/23592)) ([259b135](https://github.com/ionic-team/ionic/commit/259b1359dbd20d4f85036ae46901a051cd8fc98b)) - - - -# [6.0.0-beta.1](https://github.com/ionic-team/ionic/compare/v5.6.11...v6.0.0-beta.1) (2021-07-01) - - -### Bug Fixes - -* **accordion:** improved reliability of accordion animations ([#23531](https://github.com/ionic-team/ionic/issues/23531)) ([6fbd60b](https://github.com/ionic-team/ionic/commit/6fbd60b0df56dc927226474a1ffa322d979c563e)), closes [#23504](https://github.com/ionic-team/ionic/issues/23504) -* **content:** add touch-action manipulation for a11y zoom and pan ([#23534](https://github.com/ionic-team/ionic/issues/23534)) ([6ca1780](https://github.com/ionic-team/ionic/commit/6ca17805b8b1ea38d7fc16d091324da16a4193c6)), closes [#22805](https://github.com/ionic-team/ionic/issues/22805) -* **datetime:** scroll position no longer gets reset when using datetime in overlay ([#23543](https://github.com/ionic-team/ionic/issues/23543)) ([b735b58](https://github.com/ionic-team/ionic/commit/b735b587cda777ac481bb580c883d9734145f31e)) -* **input, select, textarea:** change type of placeholder prop to string only ([#23500](https://github.com/ionic-team/ionic/issues/23500)) ([f3ae431](https://github.com/ionic-team/ionic/commit/f3ae4319bb64debab304973856a33e422ac910a1)), closes [#22976](https://github.com/ionic-team/ionic/issues/22976) -* **popover:** size property now works when providing only event ([#23532](https://github.com/ionic-team/ionic/issues/23532)) ([bdc1f23](https://github.com/ionic-team/ionic/commit/bdc1f2360d7795472cc242a86eb4376d05fa0bb7)), closes [#23528](https://github.com/ionic-team/ionic/issues/23528) -* **popover:** update animation to better match MD spec ([#23541](https://github.com/ionic-team/ionic/issues/23541)) ([bdb95b7](https://github.com/ionic-team/ionic/commit/bdb95b7b6dd798cbc6d1786ae54fa95ac1dfd096)) -* **react:** export accordion and accordion group components ([#23497](https://github.com/ionic-team/ionic/issues/23497)) ([a664d42](https://github.com/ionic-team/ionic/commit/a664d4268dea8e84ab9e3b150043ac8f87fb53c7)) -* **vue:** navigating between parameterized pages now results in page transition ([#23525](https://github.com/ionic-team/ionic/issues/23525)) ([e30b17c](https://github.com/ionic-team/ionic/commit/e30b17c5bbd1af6936a8d7a98d1f7a115073e029)), closes [#22662](https://github.com/ionic-team/ionic/issues/22662) - - -### Features - -* **accordion-group:** add animated property to disable animations ([#23530](https://github.com/ionic-team/ionic/issues/23530)) ([9a60dd0](https://github.com/ionic-team/ionic/commit/9a60dd0ea7c55acf0fdd1161433e5b4ed40778f2)) -* **action-sheet, alert:** add id to AlertButton and ActionSheetButton ([#18992](https://github.com/ionic-team/ionic/issues/18992)) ([9e24a0b](https://github.com/ionic-team/ionic/commit/9e24a0b49357a3a39ca89f026ff23271a365d935)), closes [#22959](https://github.com/ionic-team/ionic/issues/22959) -* **vue:** extend useIonRouter hook for programmatic navigation with animation control ([#23499](https://github.com/ionic-team/ionic/issues/23499)) ([fc9e1b4](https://github.com/ionic-team/ionic/commit/fc9e1b4b361938e5644683c395a565be2de1eab9)), closes [#23450](https://github.com/ionic-team/ionic/issues/23450) - - -### BREAKING CHANGES - -* **input, select, textarea:** Updated the `placeholder` property on `ion-input`, `ion-textarea`, and `ion-select` to have a type of `string | undefined`. - - - -# [6.0.0-beta.0](https://github.com/ionic-team/ionic/compare/v5.6.10...v6.0.0-beta.0) (2021-06-23) - - -### Bug Fixes - -* **accordion:** toggle icon now shows up in vue and react ([#23426](https://github.com/ionic-team/ionic/issues/23426)) ([c716617](https://github.com/ionic-team/ionic/commit/c7166179457a8e2c7e1702c5761bc6368dbd156f)) -* **datetime:** changing time emits ionChange ([#23463](https://github.com/ionic-team/ionic/issues/23463)) ([b0cce36](https://github.com/ionic-team/ionic/commit/b0cce360c83ac564e053523cc31b32d1deaeda0c)) -* **modal:** add additional padding to toolbars in iOS modal ([#23262](https://github.com/ionic-team/ionic/issues/23262)) ([a037b65](https://github.com/ionic-team/ionic/commit/a037b65aad5cfc0477322a8f36105b9009366ec2)), closes [#22778](https://github.com/ionic-team/ionic/issues/22778) -* **modal:** border radius is correctly set on card style modal ([#23461](https://github.com/ionic-team/ionic/issues/23461)) ([bccb8ad](https://github.com/ionic-team/ionic/commit/bccb8ad5fb5ec7f98a6cbfa62a403ecaca7fbdb6)) -* **modal, popover:** overlays now automatically determine if they are inline ([#23434](https://github.com/ionic-team/ionic/issues/23434)) ([8dbe8ba](https://github.com/ionic-team/ionic/commit/8dbe8ba7bc26792c5024f81cf4752f5b78317492)) -* **popover:** shadow parts now correctly added ([#23446](https://github.com/ionic-team/ionic/issues/23446)) ([e1a9613](https://github.com/ionic-team/ionic/commit/e1a96130ebab1e481e880f0f3876f421976f08d5)) -* **popover:** update prop defaults, use correct delegate ([#23340](https://github.com/ionic-team/ionic/issues/23340)) ([960778a](https://github.com/ionic-team/ionic/commit/960778a36f6eb6318cc740c4f7a255107723b8fd)) -* **searchbar:** showClearButton now defaults to 'always' for improved usability with screen readers ([#23475](https://github.com/ionic-team/ionic/issues/23475)) ([80f181d](https://github.com/ionic-team/ionic/commit/80f181d4846507ee6bd4150bb568fca9b6660428)) -* **vue:** ensure webpack does not eliminate core css ([#23465](https://github.com/ionic-team/ionic/issues/23465)) ([ee3a00f](https://github.com/ionic-team/ionic/commit/ee3a00fde61b4d1d3168d34b3d23bb97dd154154)) - - -### Code Refactoring - -* **all:** update required browser, framework, and mobile platform versions for v6 ([#23443](https://github.com/ionic-team/ionic/issues/23443)) ([c842dd8](https://github.com/ionic-team/ionic/commit/c842dd88c98888b2afab08ac5e8bc57c2a4c2fbd)) -* **angular:** remove Config.set() method ([#22918](https://github.com/ionic-team/ionic/issues/22918)) ([9e05891](https://github.com/ionic-team/ionic/commit/9e0589173607b3c0eff7794079123354c2eeaa1a)) -* **header:** removed border from last toolbar when using collapsible large title ([#22891](https://github.com/ionic-team/ionic/issues/22891)) ([c72bc5d](https://github.com/ionic-team/ionic/commit/c72bc5dbd76cd3ce622a4b3cedcb7446a2819384)), closes [#22777](https://github.com/ionic-team/ionic/issues/22777) -* **ios:** update toolbar and tabbar default background colors ([#22852](https://github.com/ionic-team/ionic/issues/22852)) ([3d615cb](https://github.com/ionic-team/ionic/commit/3d615cb3c7b233b08b9da6ac04096e16bbb60bfc)), closes [#22780](https://github.com/ionic-team/ionic/issues/22780) -* **toast:** whitespace variable now defaults to normal ([#22866](https://github.com/ionic-team/ionic/issues/22866)) ([9b78689](https://github.com/ionic-team/ionic/commit/9b786899e550c391b9395c669f9bba8f39ac98aa)) -* **vue:** drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6 ([#23229](https://github.com/ionic-team/ionic/issues/23229)) ([6fcb3a6](https://github.com/ionic-team/ionic/commit/6fcb3a62b1b12c5ded11179e83854592d4309bdf)) -* **vue:** remove support for child routes nested inside of tabs ([#22919](https://github.com/ionic-team/ionic/issues/22919)) ([75458ac](https://github.com/ionic-team/ionic/commit/75458ac7fb95f56a6ec460f85cf7d7720ce0c070)) - - -### Features - -* **accordion:** add accordion and accordion-group components ([#22865](https://github.com/ionic-team/ionic/issues/22865)) ([073883a](https://github.com/ionic-team/ionic/commit/073883a0987149e9f6258ca43c46f5ed4bce0dc5)), closes [#17094](https://github.com/ionic-team/ionic/issues/17094) -* **breadcrumbs:** add breadcrumbs component ([#22701](https://github.com/ionic-team/ionic/issues/22701)) ([2f6b1e4](https://github.com/ionic-team/ionic/commit/2f6b1e4eea307c6f14345704e5824378ef079acb)), closes [#22770](https://github.com/ionic-team/ionic/issues/22770) -* **datetime:** add calendar picker ([#23416](https://github.com/ionic-team/ionic/issues/23416)) ([932d3ca](https://github.com/ionic-team/ionic/commit/932d3ca62f3e3ef08acb065ce6ec46faa3811f96)), closes [#19423](https://github.com/ionic-team/ionic/issues/19423) -* **item:** add helper text, error text, counter, shape, and fill mode ([#23354](https://github.com/ionic-team/ionic/issues/23354)) ([faefe97](https://github.com/ionic-team/ionic/commit/faefe97da6a9d5beff1183d10efd0df9c4e3ebd7)), closes [#19619](https://github.com/ionic-team/ionic/issues/19619) -* **modal:** modals can now be used inline ([#23341](https://github.com/ionic-team/ionic/issues/23341)) ([3be1c3d](https://github.com/ionic-team/ionic/commit/3be1c3dcd73e6039a89b19b409e63877cda37f6e)), closes [#20117](https://github.com/ionic-team/ionic/issues/20117) [#20263](https://github.com/ionic-team/ionic/issues/20263) -* **popover:** account for ionShadowTarget elements ([#23436](https://github.com/ionic-team/ionic/issues/23436)) ([0e38d42](https://github.com/ionic-team/ionic/commit/0e38d4276110dcd94db5adc3b6aee3b5b0befc5c)) -* **popover:** add desktop support ([#23258](https://github.com/ionic-team/ionic/issues/23258)) ([a67a0fa](https://github.com/ionic-team/ionic/commit/a67a0fabb8249685bbe93ed862839e2b2e76cd5a)), closes [#21599](https://github.com/ionic-team/ionic/issues/21599) -* **popover:** popover can now be used inline ([#23231](https://github.com/ionic-team/ionic/issues/23231)) ([308fa1c](https://github.com/ionic-team/ionic/commit/308fa1c0dd054cfc2ea54d2edc99e7a4b549f6f0)) -* **slides:** add IonicSwiper modules, deprecate ion-slides, and add link to migration ([#23447](https://github.com/ionic-team/ionic/issues/23447)) ([623c84a](https://github.com/ionic-team/ionic/commit/623c84ab082668a996c654e18ffc9768f68b85dd)) -* **spinner:** add lines-sharp, lines-sharp-small, update styles for ios 14 ([#22397](https://github.com/ionic-team/ionic/issues/22397)) ([2a5b272](https://github.com/ionic-team/ionic/commit/2a5b272a329bbad1ca07705f84f0fd06e3ef32ad)) -* **vue:** add custom elements bundle ([#23458](https://github.com/ionic-team/ionic/issues/23458)) ([dc48a9f](https://github.com/ionic-team/ionic/commit/dc48a9f1a2dff8a2d644112bbe1df8b0b6811848)) - - -### BREAKING CHANGES - -* **searchbar:** The `showClearButton` property on `ion-searchbar` now defaults to `'always'`. -* **datetime:** The `ion-datetime` component has been revamped to use a new calendar style. As a result, some APIs have been removed. See https://github.com/ionic-team/ionic-framework/blob/master/BREAKING.md for more details. -* **all:** Browser, JS Framework, and mobile platform minimum required versions have been updated. -* **popover:** Converted `ion-popover` to use the Shadow DOM. -* **vue:** - Dropped support for prefixed overlay events in favor of non prefixed events (I.e. `@onDidDismiss` becomes `@didDismiss`). -- Minimum required version of Vue is now Vue v3.0.6 or newer. -* **vue:** Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix. -* **angular:** The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform. -* **ios:** The tab bar and toolbar default background colors have been updated to better reflect the latest iOS styles. -* **header:** The last toolbar in the header with a collapsible large title no longer has a border. -* **toast:** The `--white-space` CSS Variable now defaults to `normal`. - - - ## [5.6.13](https://github.com/ionic-team/ionic/compare/v5.6.12...v5.6.13) (2021-08-04) @@ -142,14 +41,14 @@ -# [6.0.0-beta.2](https://github.com/ionic-team/ionic/compare/v5.6.12...v6.0.0-beta.2) (2021-07-21) +# [6.0.0-beta.2](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2021-07-21) ### Bug Fixes * **accordion:** value can now be set as string when using multiple is true ([#23581](https://github.com/ionic-team/ionic/issues/23581)) ([8f172de](https://github.com/ionic-team/ionic/commit/8f172de355bc7c910d600ce4d8446b04a6212545)), closes [#23550](https://github.com/ionic-team/ionic/issues/23550) * **angular:** modal and popover now have correct props defined on angular component ([#23565](https://github.com/ionic-team/ionic/issues/23565)) ([e5a7b34](https://github.com/ionic-team/ionic/commit/e5a7b342623b159d41cc83e0a418fb3984ceb3a7)) -* **datetime:** keyboard can now be used to navigate between years ([#23585](https://github.com/ionic-team/ionic/issues/23585)) ([55bd1f7](https://github.com/ionic-team/ionic/commit/55bd1f749bac01cc691e16283728c42e755cc706)), closes [#21553](https://github.com/ionic-team/ionic/issues/21553) [#18122](https://github.com/ionic-team/ionic/issues/18122) +* **datetime:** add keyboard year navigation ([#23585](https://github.com/ionic-team/ionic/issues/23585)) ([55bd1f7](https://github.com/ionic-team/ionic/commit/55bd1f749bac01cc691e16283728c42e755cc706)), closes [#21553](https://github.com/ionic-team/ionic/issues/21553) [#18122](https://github.com/ionic-team/ionic/issues/18122) * **datetime:** selecting time now works correctly on firefox ([#23583](https://github.com/ionic-team/ionic/issues/23583)) ([4188964](https://github.com/ionic-team/ionic/commit/4188964dc8da2c46494245b81864ca6e305611f5)), closes [#23545](https://github.com/ionic-team/ionic/issues/23545) * **datetime:** years displayed now more consistent with v5 datetime, max and min are now accounted for in MD mode ([#23616](https://github.com/ionic-team/ionic/issues/23616)) ([be219a2](https://github.com/ionic-team/ionic/commit/be219a2814800927e6328ff105616713003340b7)), closes [#23615](https://github.com/ionic-team/ionic/issues/23615) @@ -184,7 +83,7 @@ -# [6.0.0-beta.1](https://github.com/ionic-team/ionic/compare/v5.6.11...v6.0.0-beta.1) (2021-07-01) +# [6.0.0-beta.1](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.0...v6.0.0-beta.1) (2021-07-01) ### Bug Fixes @@ -278,59 +177,6 @@ * **toast:** The `--white-space` CSS Variable now defaults to `normal`. - -# [6.0.0-beta.0](https://github.com/ionic-team/ionic/compare/v5.6.10...v6.0.0-beta.0) (2021-06-23) - -### Bug Fixes - -* **modal:** add additional padding to toolbars in iOS modal ([#23262](https://github.com/ionic-team/ionic/issues/23262)) ([a037b65](https://github.com/ionic-team/ionic/commit/a037b65aad5cfc0477322a8f36105b9009366ec2)), closes [#22778](https://github.com/ionic-team/ionic/issues/22778) -* **searchbar:** showClearButton now defaults to 'always' for improved usability with screen readers ([#23475](https://github.com/ionic-team/ionic/issues/23475)) ([80f181d](https://github.com/ionic-team/ionic/commit/80f181d4846507ee6bd4150bb568fca9b6660428)) -* **toast:** whitespace variable now defaults to normal ([#22866](https://github.com/ionic-team/ionic/issues/22866)) ([9b78689](https://github.com/ionic-team/ionic/commit/9b786899e550c391b9395c669f9bba8f39ac98aa)) -* **header:** removed border from last toolbar when using collapsible large title ([#22891](https://github.com/ionic-team/ionic/issues/22891)) ([c72bc5d](https://github.com/ionic-team/ionic/commit/c72bc5dbd76cd3ce622a4b3cedcb7446a2819384)), closes [#22777](https://github.com/ionic-team/ionic/issues/22777) -* **ios:** update toolbar and tabbar default background colors ([#22852](https://github.com/ionic-team/ionic/issues/22852)) ([3d615cb](https://github.com/ionic-team/ionic/commit/3d615cb3c7b233b08b9da6ac04096e16bbb60bfc)), closes [#22780](https://github.com/ionic-team/ionic/issues/22780) - -### Code Refactoring - -* **all:** update required browser, framework, and mobile platform versions for v6 ([#23443](https://github.com/ionic-team/ionic/issues/23443)) ([c842dd8](https://github.com/ionic-team/ionic/commit/c842dd88c98888b2afab08ac5e8bc57c2a4c2fbd)) -* **angular:** remove Config.set() method ([#22918](https://github.com/ionic-team/ionic/issues/22918)) ([9e05891](https://github.com/ionic-team/ionic/commit/9e0589173607b3c0eff7794079123354c2eeaa1a)) -* **vue:** drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6 ([#23229](https://github.com/ionic-team/ionic/issues/23229)) ([6fcb3a6](https://github.com/ionic-team/ionic/commit/6fcb3a62b1b12c5ded11179e83854592d4309bdf)) -* **vue:** remove support for child routes nested inside of tabs ([#22919](https://github.com/ionic-team/ionic/issues/22919)) ([75458ac](https://github.com/ionic-team/ionic/commit/75458ac7fb95f56a6ec460f85cf7d7720ce0c070)) - - -### Features - -* **accordion:** add accordion and accordion-group components ([#22865](https://github.com/ionic-team/ionic/issues/22865)) ([073883a](https://github.com/ionic-team/ionic/commit/073883a0987149e9f6258ca43c46f5ed4bce0dc5)), closes [#17094](https://github.com/ionic-team/ionic/issues/17094) -* **breadcrumbs:** add breadcrumbs component ([#22701](https://github.com/ionic-team/ionic/issues/22701)) ([2f6b1e4](https://github.com/ionic-team/ionic/commit/2f6b1e4eea307c6f14345704e5824378ef079acb)), closes [#22770](https://github.com/ionic-team/ionic/issues/22770) -* **datetime:** add calendar picker ([#23416](https://github.com/ionic-team/ionic/issues/23416)) ([932d3ca](https://github.com/ionic-team/ionic/commit/932d3ca62f3e3ef08acb065ce6ec46faa3811f96)), closes [#19423](https://github.com/ionic-team/ionic/issues/19423) -* **item:** add helper text, error text, counter, shape, and fill mode ([#23354](https://github.com/ionic-team/ionic/issues/23354)) ([faefe97](https://github.com/ionic-team/ionic/commit/faefe97da6a9d5beff1183d10efd0df9c4e3ebd7)), closes [#19619](https://github.com/ionic-team/ionic/issues/19619) -* **modal:** modals can now be used inline ([#23341](https://github.com/ionic-team/ionic/issues/23341)) ([3be1c3d](https://github.com/ionic-team/ionic/commit/3be1c3dcd73e6039a89b19b409e63877cda37f6e)), closes [#20117](https://github.com/ionic-team/ionic/issues/20117) [#20263](https://github.com/ionic-team/ionic/issues/20263) -* **popover:** add desktop support ([#23258](https://github.com/ionic-team/ionic/issues/23258)) ([a67a0fa](https://github.com/ionic-team/ionic/commit/a67a0fabb8249685bbe93ed862839e2b2e76cd5a)), closes [#21599](https://github.com/ionic-team/ionic/issues/21599) -* **popover:** popover can now be used inline ([#23231](https://github.com/ionic-team/ionic/issues/23231)) ([308fa1c](https://github.com/ionic-team/ionic/commit/308fa1c0dd054cfc2ea54d2edc99e7a4b549f6f0)) -* **slides:** add IonicSwiper modules, deprecate ion-slides, and add link to migration ([#23447](https://github.com/ionic-team/ionic/issues/23447)) ([623c84a](https://github.com/ionic-team/ionic/commit/623c84ab082668a996c654e18ffc9768f68b85dd)) -* **spinner:** add lines-sharp, lines-sharp-small, update styles for ios ([#22397](https://github.com/ionic-team/ionic/issues/22397)) ([2a5b272](https://github.com/ionic-team/ionic/commit/2a5b272a329bbad1ca07705f84f0fd06e3ef32ad)) -* **vue:** add custom elements bundle ([#23458](https://github.com/ionic-team/ionic/issues/23458)) ([dc48a9f](https://github.com/ionic-team/ionic/commit/dc48a9f1a2dff8a2d644112bbe1df8b0b6811848)) - -Be on the lookout for additional features and bug fixes in future beta releases of Framework v6! - -### BREAKING CHANGES - -> We recommend updating to the latest version of 5.x before trying out version 6 in order to see deprecation warnings related to your app [in the developer console](https://javascript.info/devtools). - -* **all:** Browser, JS Framework, and mobile platform minimum required versions have been updated. -* **angular:** The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform. -* **datetime:** The `ion-datetime` component has been revamped to use a new calendar style. As a result, some APIs have been removed. See https://github.com/ionic-team/ionic-framework/blob/master/BREAKING.md for more details. -* **header:** The last toolbar in the header with a collapsible large title no longer has a border. -* **ios:** The tab bar and toolbar default background colors have been updated to better reflect the latest iOS styles. -* **popover:** Converted `ion-popover` to use the Shadow DOM. -* **searchbar:** The `showClearButton` property on `ion-searchbar` now defaults to `'always'`. -* **toast:** The `--white-space` CSS Variable now defaults to `normal`. -* **vue:** - Dropped support for prefixed overlay events in favor of non prefixed events (I.e. `@onDidDismiss` becomes `@didDismiss`). -* **vue:** Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix. - -Please see the [BREAKING.md](./BREAKING.md#version-6x) file for a complete list of breaking changes in Framework v6. - - - ## [5.6.10](https://github.com/ionic-team/ionic/compare/v5.6.9...v5.6.10) (2021-06-22) diff --git a/angular/package-lock.json b/angular/package-lock.json index b8f3d92456..995d002e07 100644 --- a/angular/package-lock.json +++ b/angular/package-lock.json @@ -2033,9 +2033,9 @@ } }, "node_modules/ionicons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz", - "integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz", + "integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==", "dependencies": { "@stencil/core": "^2.5.0" } @@ -6662,9 +6662,9 @@ "dev": true }, "ionicons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz", - "integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz", + "integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==", "requires": { "@stencil/core": "^2.5.0" } diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000000..a4f4369773 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['@commitlint/config-conventional'] +} diff --git a/core/src/components/back-button/back-button.scss b/core/src/components/back-button/back-button.scss index 97e3342af4..9876135285 100644 --- a/core/src/components/back-button/back-button.scss +++ b/core/src/components/back-button/back-button.scss @@ -92,6 +92,13 @@ font-kerning: none; } +// Back Button Ripple effect +// -------------------------------------------------- + +ion-ripple-effect { + color: var(--ripple-color); +} + // Back Button with Color // -------------------------------------------------- @@ -241,4 +248,4 @@ ion-icon { :host(.in-toolbar:not(.in-toolbar-color)) { color: #{var(--ion-toolbar-color, var(--color))}; -} \ No newline at end of file +} diff --git a/core/src/components/back-button/test/basic/index.html b/core/src/components/back-button/test/basic/index.html index 23bf417c0f..7037ca5819 100644 --- a/core/src/components/back-button/test/basic/index.html +++ b/core/src/components/back-button/test/basic/index.html @@ -78,6 +78,8 @@ + +

@@ -195,6 +197,10 @@ --ion-toolbar-background: #222; --ion-toolbar-color: #ddd; } + + .ripple { + --ripple-color: red; + } diff --git a/core/src/components/img/img.tsx b/core/src/components/img/img.tsx index 80947ea17c..0f8c81ea85 100644 --- a/core/src/components/img/img.tsx +++ b/core/src/components/img/img.tsx @@ -60,10 +60,12 @@ export class Img implements ComponentInterface { 'isIntersecting' in window.IntersectionObserverEntry.prototype) { this.removeIO(); this.io = new IntersectionObserver(data => { - // because there will only ever be one instance - // of the element we are observing - // we can just use data[0] - if (data[0].isIntersecting) { + /** + * On slower devices, it is possible for an intersection observer entry to contain multiple + * objects in the array. This happens when quickly scrolling an image into view and then out of + * view. In this case, the last object represents the current state of the component. + */ + if (data[data.length - 1].isIntersecting) { this.load(); this.removeIO(); } diff --git a/core/src/components/item-option/item-option.tsx b/core/src/components/item-option/item-option.tsx index 6249862e84..25f9592fea 100644 --- a/core/src/components/item-option/item-option.tsx +++ b/core/src/components/item-option/item-option.tsx @@ -104,7 +104,7 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn [mode]: true, 'item-option-disabled': disabled, 'item-option-expandable': expandable, - 'ion-activatable': true, + 'ion-activatable': true })} > 0) diff --git a/core/src/components/nav/nav.tsx b/core/src/components/nav/nav.tsx index 7bedccf67f..b75fceae01 100644 --- a/core/src/components/nav/nav.tsx +++ b/core/src/components/nav/nav.tsx @@ -872,14 +872,15 @@ export class Nav implements NavOutlet { mode, showGoBack: this.canGoBackSync(enteringView), baseEl: this.el, - animationBuilder: this.animation || opts.animationBuilder || config.get('navAnimation'), progressCallback, animated: this.animated && config.getBoolean('animated', true), enteringEl, leavingEl, - ...opts + ...opts, + + animationBuilder: opts.animationBuilder || this.animation || config.get('navAnimation') }; const { hasCompleted } = await transition(animationOpts); return this.transitionFinish(hasCompleted, enteringView, leavingView, opts); diff --git a/core/src/components/router-outlet/route-outlet.tsx b/core/src/components/router-outlet/route-outlet.tsx index fe81399802..5e8e036e51 100644 --- a/core/src/components/router-outlet/route-outlet.tsx +++ b/core/src/components/router-outlet/route-outlet.tsx @@ -188,7 +188,7 @@ export class RouterOutlet implements ComponentInterface, NavOutlet { const { el, mode } = this; const animated = this.animated && config.getBoolean('animated', true); - const animationBuilder = this.animation || opts.animationBuilder || config.get('navAnimation'); + const animationBuilder = opts.animationBuilder || this.animation || config.get('navAnimation'); await transition({ mode, diff --git a/package.json b/package.json index 0cbb502044..d5a20dabf6 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,16 @@ "changelog": "conventional-changelog -p angular -i ./CHANGELOG.md -k core -s" }, "devDependencies": { + "@commitlint/cli": "^13.1.0", + "@commitlint/config-conventional": "^13.1.0", "@octokit/rest": "^17.11.2", "colorette": "^1.2.1", + "commitizen": "^4.2.4", "conventional-changelog-cli": "^2.1.1", + "cz-conventional-changelog": "^3.3.0", "execa": "^0.10.0", "fs-extra": "^7.0.0", + "husky": "^4.3.8", "inquirer": "^6.0.0", "listr": "^0.14.0", "rimraf": "^2.6.3", @@ -21,5 +26,16 @@ }, "engines": { "node": ">= 10" + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } + }, + "husky": { + "hooks": { + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", + "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true" + } } } diff --git a/packages/angular-server/package-lock.json b/packages/angular-server/package-lock.json index c1c4a3b1ad..9dec77c852 100644 --- a/packages/angular-server/package-lock.json +++ b/packages/angular-server/package-lock.json @@ -2411,9 +2411,9 @@ } }, "node_modules/ionicons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz", - "integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz", + "integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==", "dev": true, "dependencies": { "@stencil/core": "^2.5.0" @@ -7339,9 +7339,9 @@ "dev": true }, "ionicons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz", - "integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz", + "integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==", "dev": true, "requires": { "@stencil/core": "^2.5.0" diff --git a/packages/vue-router/__tests__/locationHistory.spec.ts b/packages/vue-router/__tests__/locationHistory.spec.ts index 9079b3cc15..f451e0eb35 100644 --- a/packages/vue-router/__tests__/locationHistory.spec.ts +++ b/packages/vue-router/__tests__/locationHistory.spec.ts @@ -15,7 +15,7 @@ describe('Location History', () => { locationHistory.add({ pathname: '/home' }); locationHistory.add({ pathname: '/login', routerAction: 'replace' }); - const current = locationHistory.current(); + const current = locationHistory.last(); expect(current.pathname).toEqual('/login'); }); @@ -23,7 +23,7 @@ describe('Location History', () => { locationHistory.add({ pathname: '/home' }); locationHistory.add({ pathname: '/login', routerAction: 'pop' }); - const current = locationHistory.current(); + const current = locationHistory.last(); expect(current.pathname).toEqual('/login'); expect(locationHistory.canGoBack(1)).toEqual(false); }); @@ -33,7 +33,7 @@ describe('Location History', () => { locationHistory.add({ pathname: '/login' }); locationHistory.add({ pathname: '/logout', routerDirection: 'root' }); - const current = locationHistory.current(); + const current = locationHistory.last(); expect(current.pathname).toEqual('/logout'); expect(locationHistory.canGoBack(1)).toEqual(false); }); @@ -42,12 +42,12 @@ describe('Location History', () => { locationHistory.add({ id: '1', pathname: '/tabs/tab1', tab: 'tab1' }); locationHistory.add({ id: '2', pathname: '/tabs/tab2' }); - const current = { ...locationHistory.current() }; + const current = { ...locationHistory.last() }; current.tab = 'tab2'; locationHistory.update(current); - const getCurrentAgain = locationHistory.current(); + const getCurrentAgain = locationHistory.last(); expect(getCurrentAgain.tab).toEqual('tab2'); }); @@ -73,7 +73,7 @@ describe('Location History', () => { locationHistory.add({ pathname: '/home' }); locationHistory.add({ pathname: '/login' }); - const current = locationHistory.current(); + const current = locationHistory.last(); expect(current.pathname).toEqual('/login'); const previous = locationHistory.previous(); diff --git a/packages/vue-router/__tests__/viewStacks.spec.ts b/packages/vue-router/__tests__/viewStacks.spec.ts index 50f265cab3..a31a466565 100644 --- a/packages/vue-router/__tests__/viewStacks.spec.ts +++ b/packages/vue-router/__tests__/viewStacks.spec.ts @@ -102,10 +102,39 @@ describe('View Stacks', () => { const viewItemsAgain = viewStacks.getViewStack(2); expect(viewItemsAgain).toEqual(undefined); - }) + }); + + it('should unmount orphaned views', () => { + const itemA = createRegisteredViewItem(viewStacks, 1, '/home/1', true); + const itemB = createRegisteredViewItem(viewStacks, 1, '/home/2', true); + const itemC = createRegisteredViewItem(viewStacks, 1, '/home/3', true); + const itemD = createRegisteredViewItem(viewStacks, 1, '/home/4', true); + + viewStacks.unmountLeavingViews(1, itemA, itemD); + + expect(itemB.mount).toEqual(false); + expect(itemB.ionPageElement).toEqual(undefined); + expect(itemB.ionRoute).toEqual(false); + + expect(itemC.mount).toEqual(false); + expect(itemC.ionPageElement).toEqual(undefined); + expect(itemC.ionRoute).toEqual(false); + }); + + it('should remount intermediary views', () => { + const itemA = createRegisteredViewItem(viewStacks); + const itemB = createRegisteredViewItem(viewStacks); + const itemC = createRegisteredViewItem(viewStacks); + const itemD = createRegisteredViewItem(viewStacks); + + viewStacks.mountIntermediaryViews(1, itemD, itemA); + + expect(itemB.mount).toEqual(true); + expect(itemC.mount).toEqual(true); + }); }) -const createRegisteredViewItem = (viewStacks, outletId = '1', route = `/home/${counter++}`) => { +const createRegisteredViewItem = (viewStacks, outletId = '1', route = `/home/${counter++}`, mount = false) => { const item = viewStacks.createViewItem( outletId, () => {}, @@ -115,10 +144,15 @@ const createRegisteredViewItem = (viewStacks, outletId = '1', route = `/home/${c viewStacks.add(item); - const ionPage = document.createElement('div'); - ionPage.classList.add('ion-page'); + if (mount) { + const ionPage = document.createElement('div'); + ionPage.classList.add('ion-page'); - viewStacks.registerIonPage(item, ionPage); + viewStacks.registerIonPage(item, ionPage); + + item.mount = true; + item.ionRoute = true; + } return item; } diff --git a/packages/vue-router/src/locationHistory.ts b/packages/vue-router/src/locationHistory.ts index f47401e1f3..3d242fe540 100644 --- a/packages/vue-router/src/locationHistory.ts +++ b/packages/vue-router/src/locationHistory.ts @@ -102,8 +102,33 @@ export const createLocationHistory = () => { return history; } - const previous = () => locationHistory[locationHistory.length - 2] || current(); - const current = () => locationHistory[locationHistory.length - 1]; + + const size = () => locationHistory.length; + + const updateByHistoryPosition = (routeInfo: RouteInfo) => { + const existingRouteIndex = locationHistory.findIndex(r => r.position === routeInfo.position); + if (existingRouteIndex === -1) return; + + locationHistory[existingRouteIndex].pathname = routeInfo.pathname; + } + + /** + * Finds and returns the location history item + * given the state of browser's history API. + * This is useful when jumping around in browser + * history using router.go. + */ + const current = (initialHistory: number, currentHistory: number) => { + /** + * initialHistory does not always start at 0 if users navigated + * to app from another website, so doing this math lets us + * find the correct index in our locationHistory array. + */ + const index = currentHistory - initialHistory; + return locationHistory[index] || last(); + } + const previous = () => locationHistory[locationHistory.length - 2] || last(); + const last = () => locationHistory[locationHistory.length - 1]; const canGoBack = (deep: number = 1) => locationHistory.length > deep; const getFirstRouteInfoForTab = (tab: string): RouteInfo | undefined => { @@ -122,23 +147,41 @@ export const createLocationHistory = () => { return undefined; } - const findLastLocation = (routeInfo: RouteInfo): RouteInfo | undefined => { + /** + * Finds and returns the previous view based upon + * what originally pushed it (pushedByRoute). + * When `delta` < -1 then we should just index into + * to array because the previous view that we want is not + * necessarily the view that pushed our current view. + * Additionally, when jumping around in history, we + * do not modify the locationHistory stack so we would + * not update pushedByRoute anyways. + */ + const findLastLocation = (routeInfo: RouteInfo, delta: number = -1): RouteInfo | undefined => { const routeInfos = getTabsHistory(routeInfo.tab); if (routeInfos) { - for (let i = routeInfos.length - 2; i >= 0; i--) { - const ri = routeInfos[i]; - if (ri) { - if (ri.pathname === routeInfo.pushedByRoute) { - return ri; + if (delta < -1) { + return routeInfos[routeInfos.length - 1 + delta]; + } else { + for (let i = routeInfos.length - 2; i >= 0; i--) { + const ri = routeInfos[i]; + if (ri) { + if (ri.pathname === routeInfo.pushedByRoute) { + return ri; + } } } } } - for (let i = locationHistory.length - 2; i >= 0; i--) { - const ri = locationHistory[i]; - if (ri) { - if (ri.pathname === routeInfo.pushedByRoute) { - return ri; + if (delta < -1) { + return locationHistory[locationHistory.length - 1 + delta]; + } else { + for (let i = locationHistory.length - 2; i >= 0; i--) { + const ri = locationHistory[i]; + if (ri) { + if (ri.pathname === routeInfo.pushedByRoute) { + return ri; + } } } } @@ -147,6 +190,9 @@ export const createLocationHistory = () => { return { current, + updateByHistoryPosition, + size, + last, previous, add, canGoBack, diff --git a/packages/vue-router/src/router.ts b/packages/vue-router/src/router.ts index 8e7d1f275b..5da52320db 100644 --- a/packages/vue-router/src/router.ts +++ b/packages/vue-router/src/router.ts @@ -19,7 +19,7 @@ import { import { AnimationBuilder } from '@ionic/vue'; export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => { - let currentNavigationInfo: NavigationInformation = { direction: undefined, action: undefined }; + let currentNavigationInfo: NavigationInformation = { direction: undefined, action: undefined, delta: undefined }; /** * Ionic Vue should only react to navigation @@ -33,7 +33,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => router.afterEach((to: RouteLocationNormalized, _: RouteLocationNormalized, failure?: NavigationFailure) => { if (failure) return; - const { direction, action } = currentNavigationInfo; + const { direction, action, delta } = currentNavigationInfo; /** * When calling router.replace, we are not informed @@ -43,13 +43,26 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => * We need to use opts.history rather than window.history * because window.history will be undefined when using SSR. */ - const replaceAction = opts.history.state.replaced ? 'replace' : undefined; - handleHistoryChange(to, action || replaceAction, direction); - currentNavigationInfo = { direction: undefined, action: undefined }; + currentHistoryPosition = opts.history.state.position as number; + + const replaceAction = opts.history.state.replaced ? 'replace' : undefined; + handleHistoryChange(to, action || replaceAction, direction, delta); + + currentNavigationInfo = { direction: undefined, action: undefined, delta: undefined }; }); const locationHistory = createLocationHistory(); + + /** + * Keeping track of the history position + * allows us to determine if a user is pushing + * new pages or updating history via the forward + * and back browser buttons. + */ + const initialHistoryPosition = opts.history.state.position as number; + let currentHistoryPosition = opts.history.state.position as number; + let currentRouteInfo: RouteInfo; let incomingRouteParams: RouteParams; let currentTab: string | undefined; @@ -79,14 +92,21 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => * router.beforeEach */ currentNavigationInfo = { - action: info.type, + delta: info.delta, + + /** + * Both the browser forward and backward actions + * are considered "pop" actions, but when going forward + * we want to make sure the forward animation is used. + */ + action: (info.type === 'pop' && info.delta >= 1) ? 'push' : info.type, direction: info.direction === '' ? 'forward' : info.direction }; }); const handleNavigateBack = (defaultHref?: string, routerAnimation?: AnimationBuilder) => { // todo grab default back button href from config - const routeInfo = locationHistory.current(); + const routeInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition); if (routeInfo && routeInfo.pushedByRoute) { const prevInfo = locationHistory.findLastLocation(routeInfo); if (prevInfo) { @@ -127,16 +147,23 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => } // TODO RouteLocationNormalized - const handleHistoryChange = (location: any, action?: RouteAction, direction?: RouteDirection) => { + const handleHistoryChange = ( + location: any, + action?: RouteAction, + direction?: RouteDirection, + delta?: number + ) => { let leavingLocationInfo: RouteInfo; if (incomingRouteParams) { if (incomingRouteParams.routerAction === 'replace') { leavingLocationInfo = locationHistory.previous(); + } else if (incomingRouteParams.routerAction === 'pop') { + leavingLocationInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition + 1); } else { - leavingLocationInfo = locationHistory.current(); + leavingLocationInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition - 1); } } else { - leavingLocationInfo = locationHistory.current(); + leavingLocationInfo = currentRouteInfo; } if (!leavingLocationInfo) { @@ -156,9 +183,10 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => tab: currentTab } } else if (action === 'pop') { - const routeInfo = locationHistory.current(); + const routeInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition - delta); + if (routeInfo && routeInfo.pushedByRoute) { - const prevRouteInfo = locationHistory.findLastLocation(routeInfo); + const prevRouteInfo = locationHistory.findLastLocation(routeInfo, delta); incomingRouteParams = { ...prevRouteInfo, routerAction: 'pop', @@ -187,7 +215,6 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => ...incomingRouteParams, lastPathname: leavingLocationInfo.pathname } - locationHistory.add(routeInfo); } else { const isPushed = incomingRouteParams.routerAction === 'push' && incomingRouteParams.routerDirection === 'forward'; @@ -211,7 +238,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => const lastRoute = locationHistory.getCurrentRouteInfoForTab(routeInfo.tab); routeInfo.pushedByRoute = lastRoute?.pushedByRoute; } else if (routeInfo.routerAction === 'replace') { - const currentRouteInfo = locationHistory.current(); + const currentRouteInfo = locationHistory.last(); /** * If going from /home to /child, then replacing from @@ -228,8 +255,27 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname; } + } + + routeInfo.position = currentHistoryPosition; + const historySize = locationHistory.size(); + const historyDiff = currentHistoryPosition - initialHistoryPosition; + + /** + * If the size of location history is greater + * than the difference between the current history + * position and the initial history position + * then we are guaranteed to already have a history + * item for this route. In other words, a user + * is navigating within the history without pushing + * new items within the stack. + */ + if (historySize > historyDiff && routeInfo.tab === undefined) { + locationHistory.updateByHistoryPosition(routeInfo); + } else { locationHistory.add(routeInfo); } + currentRouteInfo = routeInfo; } incomingRouteParams = undefined; @@ -293,7 +339,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => const handleSetCurrentTab = (tab: string) => { currentTab = tab; - const ri = { ...locationHistory.current() }; + const ri = { ...locationHistory.last() }; if (ri.tab !== tab) { ri.tab = tab; locationHistory.update(ri); @@ -318,13 +364,19 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => setIncomingRouteParams('pop', 'back', routerAnimation); router.back() }; + const goForward = (routerAnimation?: AnimationBuilder) => { setIncomingRouteParams('push', 'forward', routerAnimation); router.forward(); } + const getLeavingRouteInfo = () => { + return locationHistory.current(initialHistoryPosition, currentHistoryPosition); + } + return { handleNavigate, + getLeavingRouteInfo, handleNavigateBack, handleSetCurrentTab, getCurrentRouteInfo, diff --git a/packages/vue-router/src/types.ts b/packages/vue-router/src/types.ts index fd9143fadd..bdd0ab1e29 100644 --- a/packages/vue-router/src/types.ts +++ b/packages/vue-router/src/types.ts @@ -26,6 +26,7 @@ export interface RouteInfo { params?: { [k: string]: any }; pushedByRoute?: string; tab?: string; + position?: number; } export interface RouteParams { @@ -69,4 +70,5 @@ export interface ExternalNavigationOptions { export interface NavigationInformation { action?: RouteAction; direction?: RouteDirection; + delta?: number; } diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index 15a4885704..199356bea1 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -140,7 +140,75 @@ export const createViewStacks = (router: Router) => { return []; } + /** + * Given a view stack and entering/leaving views, + * determine the position of each item in the stack. + * This is useful for removing/adding views in between + * the view items when navigating using router.go. + * Use this method instead of doing an `Array.findIndex` + * for both view items. + */ + const findViewIndex = (viewStack: ViewItem[], enteringViewItem: ViewItem, leavingViewItem: ViewItem) => { + let enteringIndex = -1; + let leavingIndex = -1; + + for (let i = 0; i <= viewStack.length - 1; i++) { + const viewItem = viewStack[i]; + if (viewItem === enteringViewItem) { + enteringIndex = i; + } else if (viewItem === leavingViewItem) { + leavingIndex = i; + } + + if (enteringIndex > -1 && leavingIndex > -1) { + break; + } + } + + return { enteringIndex, leavingIndex }; + } + + /** + * When navigating backwards, we need to clean up and + * leaving pages so that they are re-created if + * we ever navigate back to them. This is especially + * important when using router.go and stepping back + * multiple pages at a time. + */ + const unmountLeavingViews = (outletId: number, enteringViewItem: ViewItem, leavingViewItem: ViewItem) => { + const viewStack = viewStacks[outletId]; + if (!viewStack) return; + + const { enteringIndex: startIndex, leavingIndex: endIndex } = findViewIndex(viewStack, enteringViewItem, leavingViewItem); + + for (let i = startIndex + 1; i < endIndex; i++) { + const viewItem = viewStack[i]; + viewItem.mount = false; + viewItem.ionPageElement = undefined; + viewItem.ionRoute = false; + } + } + + /** + * When navigating forward it is possible for + * developers to step forward over multiple views. + * The intermediary views need to be remounted so that + * swipe to go back works properly. + */ + const mountIntermediaryViews = (outletId: number, enteringViewItem: ViewItem, leavingViewItem: ViewItem) => { + const viewStack = viewStacks[outletId]; + if (!viewStack) return; + + const { enteringIndex: endIndex, leavingIndex: startIndex } = findViewIndex(viewStack, enteringViewItem, leavingViewItem); + + for (let i = startIndex + 1; i < endIndex; i++) { + viewStack[i].mount = true; + } + } + return { + unmountLeavingViews, + mountIntermediaryViews, clear, findViewItemByRouteInfo, findLeavingViewItemByRouteInfo, diff --git a/packages/vue/package-lock.json b/packages/vue/package-lock.json index d2d39a2af4..d5263303f8 100644 --- a/packages/vue/package-lock.json +++ b/packages/vue/package-lock.json @@ -356,9 +356,9 @@ "dev": true }, "node_modules/ionicons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz", - "integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz", + "integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==", "dependencies": { "@stencil/core": "^2.5.0" } @@ -904,9 +904,9 @@ "dev": true }, "ionicons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz", - "integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz", + "integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==", "requires": { "@stencil/core": "^2.5.0" }, diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index 0bb7ebeb64..585a6dd5c0 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -85,13 +85,13 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({ * to respond to this gesture, so check * to make sure the view is in the outlet we want. */ - const routeInfo = ionRouter.getCurrentRouteInfo(); + const routeInfo = ionRouter.getLeavingRouteInfo(); const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); return !!enteringViewItem; } const onStart = async () => { - const routeInfo = ionRouter.getCurrentRouteInfo(); + const routeInfo = ionRouter.getLeavingRouteInfo(); const { routerAnimation } = routeInfo; const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id); const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id); @@ -274,7 +274,10 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information. leavingViewItem.mount = false; leavingViewItem.ionPageElement = undefined; leavingViewItem.ionRoute = false; + viewStacks.unmountLeavingViews(id, enteringViewItem, leavingViewItem); } + } else { + viewStacks.mountIntermediaryViews(id, enteringViewItem, leavingViewItem); } fireLifecycle(leavingViewItem.vueComponent, leavingViewItem.vueComponentRef, LIFECYCLE_DID_LEAVE); diff --git a/packages/vue/test-app/src/views/Inputs.vue b/packages/vue/test-app/src/views/Inputs.vue index cad4dcfea6..cecc76f8df 100644 --- a/packages/vue/test-app/src/views/Inputs.vue +++ b/packages/vue/test-app/src/views/Inputs.vue @@ -1,5 +1,5 @@