Compare commits

...

11 Commits

Author SHA1 Message Date
Liam DeBeasi
eebae2a65a test new step colors 2023-11-15 17:13:28 -05:00
Liam DeBeasi
aa2a7f5271 chore: sync with main
chore: sync with main
2023-11-15 12:18:04 -05:00
Liam DeBeasi
2509d565b2 chore: sync 2023-11-15 12:06:22 -05:00
Liam DeBeasi
ce89057641 refactor(angular): radio component is auto generated (#28533) 2023-11-15 12:05:17 -05:00
Liam DeBeasi
5aafd68f03 chore: remove unused code (#28503)
BREAKING CHANGE: Content no longer sets the `--background` custom property when the `.outer-content` class is set on the host.
2023-11-13 11:30:36 -05:00
Maria Hutt
098ed054b1 chore(angular): remove radio value accessor (#28386)
Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
2023-11-06 10:50:03 -08:00
Sean Perkins
7ba939fb94 fix(overlays): prevent scroll gestures when the overlay is presented (#28415)
Issue number: Resolves #23942

---------

<!-- 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 an overlay is created (inserted in the DOM), but not presented, the
scroll gesture is prevented. This behavior comes from the
`connectedCallback` of `ion-backdrop`, where the gesture is prevented as
soon as the backdrop is inserted in the DOM.

This means in situations where a developer creates an overlay, but does
not present it immediately, the user cannot scroll. This is not desired.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Scroll blocking behavior tied to the gesture has been removed from
`ion-backdrop` and implemented into the overlays directly.
- When an overlay is presented, scroll blocking is enabled on the `body`
element (the user cannot scroll on the main content).
- When the last presented overlay is dismissed, scroll blocking is
disabled on the `body` element (the user can scroll on the main
content).

## Does this introduce a breaking change?

- [x] Yes
- [ ] No

`ion-backdrop` no longer prevents scrolling on the main content when the
backdrop is either inserted into the DOM or removed from the DOM.
Developers using Ionic overlays do not need to migrate their
implementations.

Developers with custom overlays using `ion-backdrop` internally can
either use Ionic's gesture controller to disable scrolling when their
overlay is presented/dismissed or can manually add the
`backdrop-no-scroll` Ionic global class to the `body` element.

<!-- 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. -->

---------
2023-11-01 14:58:53 -04:00
Sean Perkins
6cd819a059 Merge pull request #28427 from ionic-team/sp/sync-feature-8-with-main
chore: sync with main
2023-10-29 22:55:59 -04:00
Sean Perkins
9bcee94e0b Merge remote-tracking branch 'origin/main' into sp/sync-feature-8-with-main 2023-10-27 13:05:48 -04:00
Liam DeBeasi
409df1bea5 docs(breaking): add v8 browser and platform support (#28368)
BREAKING CHANGE: The supported JS Framework and Browser/Platform versions have been revised for Ionic 8
2023-10-19 11:51:08 -04:00
Amanda Johnston
021712bd7d chore(): update BREAKING.md to prepare for Ionic 8 development (#28360)
Issue number: Internal

---------

<!-- 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 new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- v7 breaking changes moved to legacy file.
- New v8 section added to main breaking changes list.

## 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. -->
2023-10-17 09:07:36 -05:00
24 changed files with 579 additions and 490 deletions

View File

@@ -4,338 +4,46 @@ This is a comprehensive list of the breaking changes introduced in the major ver
## Versions
- [Version 7.x](#version-7x)
- [Version 8.x](#version-8x)
- [Version 7.x](./BREAKING_ARCHIVE/v7.md)
- [Version 6.x](./BREAKING_ARCHIVE/v6.md)
- [Version 5.x](./BREAKING_ARCHIVE/v5.md)
- [Version 4.x](./BREAKING_ARCHIVE/v4.md)
- [Legacy](https://github.com/ionic-team/ionic-v3/blob/master/CHANGELOG.md)
## Version 7.x
## Version 8.x
- [Browser and Platform Support](#version-7x-browser-platform-support)
- [Components](#version-7x-components)
- [Accordion Group](#version-7x-accordion-group)
- [Action Sheet](#version-7x-action-sheet)
- [Back Button](#version-7x-back-button)
- [Button](#version-7x-button)
- [Card Header](#version-7x-card-header)
- [Checkbox](#version-7x-checkbox)
- [Datetime](#version-7x-datetime)
- [Input](#version-7x-input)
- [Item](#version-7x-item)
- [Modal](#version-7x-modal)
- [Overlays](#version-7x-overlays)
- [Picker](#version-7x-picker)
- [Radio Group](#version-7x-radio-group)
- [Range](#version-7x-range)
- [Searchbar](#version-7x-searchbar)
- [Segment](#version-7x-segment)
- [Select](#version-7x-select)
- [Slides](#version-7x-slides)
- [Textarea](#version-7x-textarea)
- [Toggle](#version-7x-toggle)
- [Virtual Scroll](#version-7x-virtual-scroll)
- [Config](#version-7x-config)
- [Types](#version-7x-types)
- [Overlay Attribute Interfaces](#version-7x-overlay-attribute-interfaces)
- [JavaScript Frameworks](#version-7x-javascript-frameworks)
- [Angular](#version-7x-angular)
- [React](#version-7x-react)
- [Vue](#version-7x-vue)
- [CSS Utilities](#version-7x-css-utilities)
- [hidden attribute](#version-7x-hidden-attribute)
- [Browser and Platform Support](#version-8x-browser-platform-support)
- [Components](#version-8x-components)
- [Content](#version-8x-content)
<h2 id="version-7x-browser-platform-support">Browser and Platform Support</h2>
<h2 id="version-8x-browser-platform-support">Browser and Platform Support</h2>
This section details the desktop browser, JavaScript framework, and mobile platform versions that are supported by Ionic 7.
This section details the desktop browser, JavaScript framework, and mobile platform versions that are supported by Ionic 8.
**Minimum Browser Versions**
| Desktop Browser | Supported Versions |
| --------------- | ----------------- |
| Chrome | 79+ |
| Safari | 14+ |
| Firefox | 70+ |
| Edge | 79+ |
| Chrome | 89+ |
| Safari | 15+ |
| Firefox | 75+ |
| Edge | 89+ |
**Minimum JavaScript Framework Versions**
| Framework | Supported Version |
| --------- | --------------------- |
| Angular | 14+ |
| Angular | 16+ |
| React | 17+ |
| Vue | 3.0.6+ |
**Minimum Mobile Platform Versions**
| Platform | Supported Version |
| -------- | ---------------------- |
| iOS | 14+ |
| Android | 5.1+ with Chromium 79+ |
| iOS | 15+ |
| Android | 5.1+ with Chromium 89+ |
<h2 id="version-7x-components">Components</h2>
<h2 id="version-8x-components">Components</h2>
<h4 id="version-7x-accordion-group">Accordion Group</h4>
<h4 id="version-8x-content">Content</h4>
- `ionChange` is no longer emitted when the `value` of `ion-accordion-group` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping the accordion header.
- Accordion Group no longer automatically adjusts the `value` property when passed an array and `multiple="false"`. Developers should update their apps to ensure they are using the API correctly.
<h4 id="version-7x-action-sheet">Action Sheet</h4>
- Action Sheet is updated to align with the design specification.
**Design tokens**
| Token | Previous Value | New Value |
| ---------- | -------------- | --------- |
| `--height` | `100%` | `auto` |
<h4 id="version-7x-button">Button</h4>
- Button is updated to align with the design specification for iOS.
**Design tokens**
| Token | Previous Value | New Value |
| ---------------------------------- | -------------- | --------- |
| `$button-ios-letter-spacing` | `-0.03em` | `0` |
| `$button-ios-clear-letter-spacing` | `0` | Removed |
| `$button-ios-height` | `2.8em` | `3.1em` |
| `$button-ios-border-radius` | `10px` | `14px` |
| `$button-ios-large-height` | `2.8em` | `3.1em` |
| `$button-ios-large-border-radius` | `12px` | `16px` |
<h4 id="version-7x-back-button">Back Button</h4>
- Back Button is updated to align with the design specification for iOS.
**Design tokens**
| Token | Previous Value | New Value |
| ------------------- | -------------- | --------- |
| `--icon-margin-end` | `-5px` | `1px` |
| `--icon-font-size` | `1.85em` | `1.6em` |
<h4 id="version-7x-card-header">Card Header</h4>
- The card header has ben changed to a flex container with direction set to `column` (top to bottom). In `ios` mode the direction is set to `column-reverse` which results in the subtitle displaying on top of the title.
<h4 id="version-7x-checkbox">Checkbox</h4>
- `ionChange` is no longer emitted when the `checked` property of `ion-checkbox` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping the checkbox.
- The `--background` and `--background-checked` CSS variables have been renamed to `--checkbox-background` and `--checkbox-background-checked` respectively.
<h4 id="version-7x-datetime">Datetime</h4>
- `ionChange` is no longer emitted when the `value` property of `ion-datetime` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping a date.
- Datetime no longer automatically adjusts the `value` property when passed an array and `multiple="false"`. Developers should update their apps to ensure they are using the API correctly.
- Datetime no longer incorrectly reports the time zone when `value` is updated. Datetime does not manage time zones, so any time zone information provided is ignored.
- Passing the empty string to the `value` property will now error as it is not a valid ISO-8601 value.
- The haptics when swiping the wheel picker are now enabled only on iOS.
<h4 id="version-7x-input">Input</h4>
- `ionChange` is no longer emitted when the `value` of `ion-input` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the input and the input losing focus, clicking the clear action within the input, or pressing the "Enter" key.
- If your application requires immediate feedback based on the user typing actively in the input, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.
- The `debounce` property's default value has changed from `0` to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.5` | `0.6` |
<h4 id="version-7x-item">Item</h4>
**Design tokens**
iOS:
| Token | Previous Value | New Value |
| --------------------- | -------------- | --------- |
| `$item-ios-font-size` | `17px` | `16px` |
| `--inner-padding-end` | `10px` | `16px` |
| `--padding-start` | `20px` | `16px` |
<h4 id="version-7x-modal">Modal</h4>
- The `swipeToClose` property has been removed in favor of `canDismiss`.
- The `canDismiss` property now defaults to `true` and can no longer be set to `undefined`.
<h4 id="version-7x-overlays">Overlays</h4>
Ionic now listens on the `keydown` event instead of the `keyup` event when determining when to dismiss overlays via the "Escape" key. Any applications that were listening on `keyup` to suppress this behavior should listen on `keydown` instead.
<h4 id="version-7x-picker">Picker</h4>
- The `refresh` key has been removed from the `PickerColumn` interface. Developers should use the `columns` property to refresh the `ion-picker` view.
<h4 id="version-7x-radio-group">Radio Group</h4>
- `ionChange` is no longer emitted when the `value` of `ion-radio-group` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping an `ion-radio` in the group.
<h4 id="version-7x-range">Range</h4>
- Range is updated to align with the design specification for supported modes.
**Design tokens**
iOS:
| Token | Previous Value | New Value |
| --------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `--bar-border-radius` | `0px` | `$range-ios-bar-border-radius` (`2px` default) |
| `--knob-size` | `28px` | `$range-ios-knob-width` (`26px` default) |
| `$range-ios-bar-height` | `2px` | `4px` |
| `$range-ios-bar-background-color` | `rgba(var(--ion-text-color-rgb, 0, 0, 0), .1)` | `var(--ion-color-step-900, #e6e6e6)` |
| `$range-ios-knob-box-shadow` | `0 3px 1px rgba(0, 0, 0, .1), 0 4px 8px rgba(0, 0, 0, .13), 0 0 0 1px rgba(0, 0, 0, .02)` | `0px 0.5px 4px rgba(0, 0, 0, 0.12), 0px 6px 13px rgba(0, 0, 0, 0.12)` |
| `$range-ios-knob-width` | `28px` | `26px` |
- `ionChange` is no longer emitted when the `value` of `ion-range` is modified externally. `ionChange` is only emitted from user committed changes, such as dragging and releasing the range knob or selecting a new value with the keyboard arrows.
- If your application requires immediate feedback based on the user actively dragging the range knob, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property's value value has changed from `0` to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- Range no longer clamps assigned values within bounds. Developers will need to validate the value they are assigning to `ion-range` is within the `min` and `max` bounds when programmatically assigning a value.
- The `name` property defaults to `ion-r-${rangeIds++}` where `rangeIds` is a number that is incremented for every instance of `ion-range`.
<h4 id="version-7x-searchbar">Searchbar</h4>
- `ionChange` is no longer emitted when the `value` of `ion-searchbar` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the searchbar and the searchbar losing focus or pressing the "Enter" key.
- If your application requires immediate feedback based on the user typing actively in the searchbar, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.
- The `debounce` property's default value has changed from 250 to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.5` | `0.6` |
<h4 id="version-7x-segment">Segment</h4>
- `ionChange` is no longer emitted when the `value` of `ion-segment` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking a segment button or dragging to activate a segment button.
- The type signature of `value` supports `string | undefined`. Previously the type signature was `string | null | undefined`.
- Developers needing to clear the checked segment item should assign a value of `''` instead of `null`.
<h4 id="version-7x-select">Select</h4>
- `ionChange` is no longer emitted when the `value` of `ion-select` is modified externally. `ionChange` is only emitted from user committed changes, such as confirming a selected option in the select's overlay.
- The `icon` CSS Shadow Part now targets an `ion-icon` component.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.33` | `0.6` |
<h4 id="version-7x-slides">Slides</h4>
`ion-slides`, `ion-slide`, and the `IonicSwiper` plugin have been removed from Ionic.
Developers using these components will need to migrate to using Swiper.js directly, optionally using the `IonicSlides` plugin. Guides for migration and usage are linked below:
- [Angular](https://ionicframework.com/docs/angular/slides)
- [React](https://ionicframework.com/docs/react/slides)
- [Vue](https://ionicframework.com/docs/vue/slides)
<h4 id="version-7x-textarea">Textarea</h4>
- `ionChange` is no longer emitted when the `value` of `ion-textarea` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the textarea and the textarea losing focus.
- If your application requires immediate feedback based on the user typing actively in the textarea, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.
- The `debounce` property's default value has changed from `0` to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- `ionInput` dispatches an event detail of `null` when the textarea is cleared as a result of `clear-on-edit="true"`.
- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.5` | `0.6` |
<h4 id="version-7x-toggle">Toggle</h4>
- `ionChange` is no longer emitted when the `checked` property of `ion-toggle` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking the toggle to set it on or off.
- The `--background` and `--background-checked` variables have been renamed to `--track-background` and `--track-background-checked`, respectively.
<h4 id="version-7x-virtual-scroll">Virtual Scroll</h4>
`ion-virtual-scroll` has been removed from Ionic.
Developers using the component will need to migrate to a virtual scroll solution provided by their framework:
- [Angular](https://ionicframework.com/docs/angular/virtual-scroll)
- [React](https://ionicframework.com/docs/react/virtual-scroll)
- [Vue](https://ionicframework.com/docs/vue/virtual-scroll)
Any references to the virtual scroll types from `@ionic/core` have been removed. Please remove or replace these types: `Cell`, `VirtualNode`, `CellType`, `NodeChange`, `HeaderFn`, `ItemHeightFn`, `FooterHeightFn`, `ItemRenderFn` and `DomRenderFn`.
<h2 id="version-7x-config">Config</h2>
- `innerHTMLTemplatesEnabled` defaults to `false`. Developers who wish to use the `innerHTML` functionality inside of `ion-alert`, `ion-infinite-scroll-content`, `ion-loading`, `ion-refresher-content`, and `ion-toast` must set this config to `true` and properly sanitize their content.
<h2 id="version-7x-types">Types</h2>
<h4 id="version-7x-overlay-attribute-interfaces">Overlay Attribute Interfaces</h4>
`ActionSheetAttributes`, `AlertAttributes`, `AlertTextareaAttributes`, `AlertInputAttributes`, `LoadingAttributes`, `ModalAttributes`, `PickerAttributes`, `PopoverAttributes`, and `ToastAttributes` have been removed. Developers should use `{ [key: string]: any }` instead.
<h2 id="version-7x-javascript-frameworks">JavaScript Frameworks</h2>
<h4 id="version-7x-angular">Angular</h4>
- Angular v14 is now required to use `@ionic/angular` and `@ionic/angular-server`. Upgrade your project to Angular v14 by following the [Angular v14 update guide](https://update.angular.io/?l=3&v=13.0-14.0).
- `null` values on form components will no longer be converted to the empty string (`''`) or `false`. This impacts `ion-checkbox`, `ion-datetime`, `ion-input`, `ion-radio`, `ion-radio-group`, `ion-range`, `ion-searchbar`, `ion-segment`, `ion-select`, `ion-textarea`, and `ion-toggle`.
- The dev-preview `environmentInjector` property has been removed from `ion-tabs` and `ion-router-outlet`. Standalone component routing is now available without additional custom configuration. Remove the `environmentInjector` property from your `ion-tabs` and `ion-router-outlet` components.
<h4 id="version-7x-react">React</h4>
`@ionic/react` and `@ionic/react-router` no longer ship a CommonJS entry point. Instead, only an ES Module entry point is provided for improved compatibility with Vite.
<h4 id="version-7x-vue">Vue</h4>
`@ionic/vue` and `@ionic/vue-router` no longer ship a CommonJS entry point. Instead, only an ES Module entry point is provided for improved compatibility with Vite.
<h2 id="version-7x-css-utilities">CSS Utilities</h2>
<h4 id="version-7x-hidden-attribute">`hidden` attribute</h4>
The `[hidden]` attribute has been removed from Ionic's global stylesheet. The `[hidden]` attribute can continue to be used, but developers will get the [native `hidden` implementation](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden) instead. The main difference is that the native implementation is easier to override using `display` than Ionic's implementation.
Developers can add the following CSS to their global stylesheet if they need the old behavior:
```css
[hidden] {
display: none !important;
}
```
- Content no longer sets the `--background` custom property when the `.outer-content` class is set on the host.

331
BREAKING_ARCHIVE/v7.md Normal file
View File

@@ -0,0 +1,331 @@
# Breaking Changes
## Version 7.x
- [Browser and Platform Support](#version-7x-browser-platform-support)
- [Components](#version-7x-components)
- [Accordion Group](#version-7x-accordion-group)
- [Action Sheet](#version-7x-action-sheet)
- [Back Button](#version-7x-back-button)
- [Button](#version-7x-button)
- [Card Header](#version-7x-card-header)
- [Checkbox](#version-7x-checkbox)
- [Datetime](#version-7x-datetime)
- [Input](#version-7x-input)
- [Item](#version-7x-item)
- [Modal](#version-7x-modal)
- [Overlays](#version-7x-overlays)
- [Picker](#version-7x-picker)
- [Radio Group](#version-7x-radio-group)
- [Range](#version-7x-range)
- [Searchbar](#version-7x-searchbar)
- [Segment](#version-7x-segment)
- [Select](#version-7x-select)
- [Slides](#version-7x-slides)
- [Textarea](#version-7x-textarea)
- [Toggle](#version-7x-toggle)
- [Virtual Scroll](#version-7x-virtual-scroll)
- [Config](#version-7x-config)
- [Types](#version-7x-types)
- [Overlay Attribute Interfaces](#version-7x-overlay-attribute-interfaces)
- [JavaScript Frameworks](#version-7x-javascript-frameworks)
- [Angular](#version-7x-angular)
- [React](#version-7x-react)
- [Vue](#version-7x-vue)
- [CSS Utilities](#version-7x-css-utilities)
- [hidden attribute](#version-7x-hidden-attribute)
<h2 id="version-7x-browser-platform-support">Browser and Platform Support</h2>
This section details the desktop browser, JavaScript framework, and mobile platform versions that are supported by Ionic 7.
**Minimum Browser Versions**
| Desktop Browser | Supported Versions |
| --------------- | ----------------- |
| Chrome | 79+ |
| Safari | 14+ |
| Firefox | 70+ |
| Edge | 79+ |
**Minimum JavaScript Framework Versions**
| Framework | Supported Version |
| --------- | --------------------- |
| Angular | 14+ |
| React | 17+ |
| Vue | 3.0.6+ |
**Minimum Mobile Platform Versions**
| Platform | Supported Version |
| -------- | ---------------------- |
| iOS | 14+ |
| Android | 5.1+ with Chromium 79+ |
<h2 id="version-7x-components">Components</h2>
<h4 id="version-7x-accordion-group">Accordion Group</h4>
- `ionChange` is no longer emitted when the `value` of `ion-accordion-group` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping the accordion header.
- Accordion Group no longer automatically adjusts the `value` property when passed an array and `multiple="false"`. Developers should update their apps to ensure they are using the API correctly.
<h4 id="version-7x-action-sheet">Action Sheet</h4>
- Action Sheet is updated to align with the design specification.
**Design tokens**
| Token | Previous Value | New Value |
| ---------- | -------------- | --------- |
| `--height` | `100%` | `auto` |
<h4 id="version-7x-button">Button</h4>
- Button is updated to align with the design specification for iOS.
**Design tokens**
| Token | Previous Value | New Value |
| ---------------------------------- | -------------- | --------- |
| `$button-ios-letter-spacing` | `-0.03em` | `0` |
| `$button-ios-clear-letter-spacing` | `0` | Removed |
| `$button-ios-height` | `2.8em` | `3.1em` |
| `$button-ios-border-radius` | `10px` | `14px` |
| `$button-ios-large-height` | `2.8em` | `3.1em` |
| `$button-ios-large-border-radius` | `12px` | `16px` |
<h4 id="version-7x-back-button">Back Button</h4>
- Back Button is updated to align with the design specification for iOS.
**Design tokens**
| Token | Previous Value | New Value |
| ------------------- | -------------- | --------- |
| `--icon-margin-end` | `-5px` | `1px` |
| `--icon-font-size` | `1.85em` | `1.6em` |
<h4 id="version-7x-card-header">Card Header</h4>
- The card header has ben changed to a flex container with direction set to `column` (top to bottom). In `ios` mode the direction is set to `column-reverse` which results in the subtitle displaying on top of the title.
<h4 id="version-7x-checkbox">Checkbox</h4>
- `ionChange` is no longer emitted when the `checked` property of `ion-checkbox` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping the checkbox.
- The `--background` and `--background-checked` CSS variables have been renamed to `--checkbox-background` and `--checkbox-background-checked` respectively.
<h4 id="version-7x-datetime">Datetime</h4>
- `ionChange` is no longer emitted when the `value` property of `ion-datetime` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping a date.
- Datetime no longer automatically adjusts the `value` property when passed an array and `multiple="false"`. Developers should update their apps to ensure they are using the API correctly.
- Datetime no longer incorrectly reports the time zone when `value` is updated. Datetime does not manage time zones, so any time zone information provided is ignored.
- Passing the empty string to the `value` property will now error as it is not a valid ISO-8601 value.
- The haptics when swiping the wheel picker are now enabled only on iOS.
<h4 id="version-7x-input">Input</h4>
- `ionChange` is no longer emitted when the `value` of `ion-input` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the input and the input losing focus, clicking the clear action within the input, or pressing the "Enter" key.
- If your application requires immediate feedback based on the user typing actively in the input, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.
- The `debounce` property's default value has changed from `0` to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.5` | `0.6` |
<h4 id="version-7x-item">Item</h4>
**Design tokens**
iOS:
| Token | Previous Value | New Value |
| --------------------- | -------------- | --------- |
| `$item-ios-font-size` | `17px` | `16px` |
| `--inner-padding-end` | `10px` | `16px` |
| `--padding-start` | `20px` | `16px` |
<h4 id="version-7x-modal">Modal</h4>
- The `swipeToClose` property has been removed in favor of `canDismiss`.
- The `canDismiss` property now defaults to `true` and can no longer be set to `undefined`.
<h4 id="version-7x-overlays">Overlays</h4>
Ionic now listens on the `keydown` event instead of the `keyup` event when determining when to dismiss overlays via the "Escape" key. Any applications that were listening on `keyup` to suppress this behavior should listen on `keydown` instead.
<h4 id="version-7x-picker">Picker</h4>
- The `refresh` key has been removed from the `PickerColumn` interface. Developers should use the `columns` property to refresh the `ion-picker` view.
<h4 id="version-7x-radio-group">Radio Group</h4>
- `ionChange` is no longer emitted when the `value` of `ion-radio-group` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking or tapping an `ion-radio` in the group.
<h4 id="version-7x-range">Range</h4>
- Range is updated to align with the design specification for supported modes.
**Design tokens**
iOS:
| Token | Previous Value | New Value |
| --------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `--bar-border-radius` | `0px` | `$range-ios-bar-border-radius` (`2px` default) |
| `--knob-size` | `28px` | `$range-ios-knob-width` (`26px` default) |
| `$range-ios-bar-height` | `2px` | `4px` |
| `$range-ios-bar-background-color` | `rgba(var(--ion-text-color-rgb, 0, 0, 0), .1)` | `var(--ion-color-step-900, #e6e6e6)` |
| `$range-ios-knob-box-shadow` | `0 3px 1px rgba(0, 0, 0, .1), 0 4px 8px rgba(0, 0, 0, .13), 0 0 0 1px rgba(0, 0, 0, .02)` | `0px 0.5px 4px rgba(0, 0, 0, 0.12), 0px 6px 13px rgba(0, 0, 0, 0.12)` |
| `$range-ios-knob-width` | `28px` | `26px` |
- `ionChange` is no longer emitted when the `value` of `ion-range` is modified externally. `ionChange` is only emitted from user committed changes, such as dragging and releasing the range knob or selecting a new value with the keyboard arrows.
- If your application requires immediate feedback based on the user actively dragging the range knob, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property's value value has changed from `0` to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- Range no longer clamps assigned values within bounds. Developers will need to validate the value they are assigning to `ion-range` is within the `min` and `max` bounds when programmatically assigning a value.
- The `name` property defaults to `ion-r-${rangeIds++}` where `rangeIds` is a number that is incremented for every instance of `ion-range`.
<h4 id="version-7x-searchbar">Searchbar</h4>
- `ionChange` is no longer emitted when the `value` of `ion-searchbar` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the searchbar and the searchbar losing focus or pressing the "Enter" key.
- If your application requires immediate feedback based on the user typing actively in the searchbar, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.
- The `debounce` property's default value has changed from 250 to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.5` | `0.6` |
<h4 id="version-7x-segment">Segment</h4>
- `ionChange` is no longer emitted when the `value` of `ion-segment` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking a segment button or dragging to activate a segment button.
- The type signature of `value` supports `string | undefined`. Previously the type signature was `string | null | undefined`.
- Developers needing to clear the checked segment item should assign a value of `''` instead of `null`.
<h4 id="version-7x-select">Select</h4>
- `ionChange` is no longer emitted when the `value` of `ion-select` is modified externally. `ionChange` is only emitted from user committed changes, such as confirming a selected option in the select's overlay.
- The `icon` CSS Shadow Part now targets an `ion-icon` component.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.33` | `0.6` |
<h4 id="version-7x-slides">Slides</h4>
`ion-slides`, `ion-slide`, and the `IonicSwiper` plugin have been removed from Ionic.
Developers using these components will need to migrate to using Swiper.js directly, optionally using the `IonicSlides` plugin. Guides for migration and usage are linked below:
- [Angular](https://ionicframework.com/docs/angular/slides)
- [React](https://ionicframework.com/docs/react/slides)
- [Vue](https://ionicframework.com/docs/vue/slides)
<h4 id="version-7x-textarea">Textarea</h4>
- `ionChange` is no longer emitted when the `value` of `ion-textarea` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the textarea and the textarea losing focus.
- If your application requires immediate feedback based on the user typing actively in the textarea, consider migrating your event listeners to using `ionInput` instead.
- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.
- The `debounce` property's default value has changed from `0` to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
- `ionInput` dispatches an event detail of `null` when the textarea is cleared as a result of `clear-on-edit="true"`.
- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
**Design tokens**
| Token | Previous Value | New Value |
| ----------------------- | -------------- | --------- |
| `--placeholder-opacity` | `0.5` | `0.6` |
<h4 id="version-7x-toggle">Toggle</h4>
- `ionChange` is no longer emitted when the `checked` property of `ion-toggle` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking the toggle to set it on or off.
- The `--background` and `--background-checked` variables have been renamed to `--track-background` and `--track-background-checked`, respectively.
<h4 id="version-7x-virtual-scroll">Virtual Scroll</h4>
`ion-virtual-scroll` has been removed from Ionic.
Developers using the component will need to migrate to a virtual scroll solution provided by their framework:
- [Angular](https://ionicframework.com/docs/angular/virtual-scroll)
- [React](https://ionicframework.com/docs/react/virtual-scroll)
- [Vue](https://ionicframework.com/docs/vue/virtual-scroll)
Any references to the virtual scroll types from `@ionic/core` have been removed. Please remove or replace these types: `Cell`, `VirtualNode`, `CellType`, `NodeChange`, `HeaderFn`, `ItemHeightFn`, `FooterHeightFn`, `ItemRenderFn` and `DomRenderFn`.
<h2 id="version-7x-config">Config</h2>
- `innerHTMLTemplatesEnabled` defaults to `false`. Developers who wish to use the `innerHTML` functionality inside of `ion-alert`, `ion-infinite-scroll-content`, `ion-loading`, `ion-refresher-content`, and `ion-toast` must set this config to `true` and properly sanitize their content.
<h2 id="version-7x-types">Types</h2>
<h4 id="version-7x-overlay-attribute-interfaces">Overlay Attribute Interfaces</h4>
`ActionSheetAttributes`, `AlertAttributes`, `AlertTextareaAttributes`, `AlertInputAttributes`, `LoadingAttributes`, `ModalAttributes`, `PickerAttributes`, `PopoverAttributes`, and `ToastAttributes` have been removed. Developers should use `{ [key: string]: any }` instead.
<h2 id="version-7x-javascript-frameworks">JavaScript Frameworks</h2>
<h4 id="version-7x-angular">Angular</h4>
- Angular v14 is now required to use `@ionic/angular` and `@ionic/angular-server`. Upgrade your project to Angular v14 by following the [Angular v14 update guide](https://update.angular.io/?l=3&v=13.0-14.0).
- `null` values on form components will no longer be converted to the empty string (`''`) or `false`. This impacts `ion-checkbox`, `ion-datetime`, `ion-input`, `ion-radio`, `ion-radio-group`, `ion-range`, `ion-searchbar`, `ion-segment`, `ion-select`, `ion-textarea`, and `ion-toggle`.
- The dev-preview `environmentInjector` property has been removed from `ion-tabs` and `ion-router-outlet`. Standalone component routing is now available without additional custom configuration. Remove the `environmentInjector` property from your `ion-tabs` and `ion-router-outlet` components.
<h4 id="version-7x-react">React</h4>
`@ionic/react` and `@ionic/react-router` no longer ship a CommonJS entry point. Instead, only an ES Module entry point is provided for improved compatibility with Vite.
<h4 id="version-7x-vue">Vue</h4>
`@ionic/vue` and `@ionic/vue-router` no longer ship a CommonJS entry point. Instead, only an ES Module entry point is provided for improved compatibility with Vite.
<h2 id="version-7x-css-utilities">CSS Utilities</h2>
<h4 id="version-7x-hidden-attribute">`hidden` attribute</h4>
The `[hidden]` attribute has been removed from Ionic's global stylesheet. The `[hidden]` attribute can continue to be used, but developers will get the [native `hidden` implementation](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden) instead. The main difference is that the native implementation is easier to override using `display` than Ionic's implementation.
Developers can add the following CSS to their global stylesheet if they need the old behavior:
```css
[hidden] {
display: none !important;
}
```

View File

@@ -1,6 +1,5 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Event, Host, Listen, Prop, h } from '@stencil/core';
import { GESTURE_CONTROLLER } from '@utils/gesture';
import { getIonMode } from '../../global/ionic-global';
@@ -13,10 +12,6 @@ import { getIonMode } from '../../global/ionic-global';
shadow: true,
})
export class Backdrop implements ComponentInterface {
private blocker = GESTURE_CONTROLLER.createBlocker({
disableScroll: true,
});
/**
* If `true`, the backdrop will be visible.
*/
@@ -37,16 +32,6 @@ export class Backdrop implements ComponentInterface {
*/
@Event() ionBackdropTap!: EventEmitter<void>;
connectedCallback() {
if (this.stopPropagation) {
this.blocker.block();
}
}
disconnectedCallback() {
this.blocker.unblock();
}
@Listen('click', { passive: false, capture: true })
protected onMouseDown(ev: TouchEvent) {
this.emitTap(ev);

View File

@@ -54,10 +54,6 @@
color: current-color(contrast);
}
:host(.outer-content) {
--background: #{$background-color-step-50};
}
#background-content {
@include position(calc(var(--offset-top) * -1), 0px,calc(var(--offset-bottom) * -1), 0px);

View File

@@ -52,7 +52,7 @@ export class Menu implements ComponentInterface, MenuI {
width!: number;
_isOpen = false;
backdropEl?: HTMLElement;
backdropEl?: HTMLIonBackdropElement;
menuInnerEl?: HTMLElement;
contentEl?: HTMLElement;
lastFocus?: HTMLElement;

View File

@@ -101,44 +101,44 @@ $text-color-rgb: var(--ion-text-color-rgb, $text-color-rgb-va
// For example, $text-color-step-XXX will be $text-color stepping towards $background-color,
// but a $background-color-step-XXX will be $background-color stepping towards $text-color.
$background-color-step-50: var(--ion-color-step-50, mix($text-color-value, $background-color-value, 5%)) !default;
$background-color-step-100: var(--ion-color-step-100, mix($text-color-value, $background-color-value, 10%)) !default;
$background-color-step-150: var(--ion-color-step-150, mix($text-color-value, $background-color-value, 15%)) !default;
$background-color-step-200: var(--ion-color-step-200, mix($text-color-value, $background-color-value, 20%)) !default;
$background-color-step-250: var(--ion-color-step-250, mix($text-color-value, $background-color-value, 25%)) !default;
$background-color-step-300: var(--ion-color-step-300, mix($text-color-value, $background-color-value, 30%)) !default;
$background-color-step-350: var(--ion-color-step-350, mix($text-color-value, $background-color-value, 35%)) !default;
$background-color-step-400: var(--ion-color-step-400, mix($text-color-value, $background-color-value, 40%)) !default;
$background-color-step-450: var(--ion-color-step-450, mix($text-color-value, $background-color-value, 45%)) !default;
$background-color-step-500: var(--ion-color-step-500, mix($text-color-value, $background-color-value, 50%)) !default;
$background-color-step-550: var(--ion-color-step-550, mix($text-color-value, $background-color-value, 55%)) !default;
$background-color-step-600: var(--ion-color-step-600, mix($text-color-value, $background-color-value, 60%)) !default;
$background-color-step-650: var(--ion-color-step-650, mix($text-color-value, $background-color-value, 65%)) !default;
$background-color-step-700: var(--ion-color-step-700, mix($text-color-value, $background-color-value, 70%)) !default;
$background-color-step-750: var(--ion-color-step-750, mix($text-color-value, $background-color-value, 75%)) !default;
$background-color-step-800: var(--ion-color-step-800, mix($text-color-value, $background-color-value, 80%)) !default;
$background-color-step-850: var(--ion-color-step-850, mix($text-color-value, $background-color-value, 85%)) !default;
$background-color-step-900: var(--ion-color-step-900, mix($text-color-value, $background-color-value, 90%)) !default;
$background-color-step-950: var(--ion-color-step-950, mix($text-color-value, $background-color-value, 95%)) !default;
$text-color-step-50: var(--ion-color-step-950, mix($background-color-value, $text-color-value, 5%)) !default;
$text-color-step-100: var(--ion-color-step-900, mix($background-color-value, $text-color-value, 10%)) !default;
$text-color-step-150: var(--ion-color-step-850, mix($background-color-value, $text-color-value, 15%)) !default;
$text-color-step-200: var(--ion-color-step-800, mix($background-color-value, $text-color-value, 20%)) !default;
$text-color-step-250: var(--ion-color-step-750, mix($background-color-value, $text-color-value, 25%)) !default;
$text-color-step-300: var(--ion-color-step-700, mix($background-color-value, $text-color-value, 30%)) !default;
$text-color-step-350: var(--ion-color-step-650, mix($background-color-value, $text-color-value, 35%)) !default;
$text-color-step-400: var(--ion-color-step-600, mix($background-color-value, $text-color-value, 40%)) !default;
$text-color-step-450: var(--ion-color-step-550, mix($background-color-value, $text-color-value, 45%)) !default;
$text-color-step-500: var(--ion-color-step-500, mix($background-color-value, $text-color-value, 50%)) !default;
$text-color-step-550: var(--ion-color-step-450, mix($background-color-value, $text-color-value, 55%)) !default;
$text-color-step-600: var(--ion-color-step-400, mix($background-color-value, $text-color-value, 60%)) !default;
$text-color-step-650: var(--ion-color-step-350, mix($background-color-value, $text-color-value, 65%)) !default;
$text-color-step-700: var(--ion-color-step-300, mix($background-color-value, $text-color-value, 70%)) !default;
$text-color-step-750: var(--ion-color-step-250, mix($background-color-value, $text-color-value, 75%)) !default;
$text-color-step-800: var(--ion-color-step-200, mix($background-color-value, $text-color-value, 80%)) !default;
$text-color-step-850: var(--ion-color-step-150, mix($background-color-value, $text-color-value, 85%)) !default;
$text-color-step-900: var(--ion-color-step-100, mix($background-color-value, $text-color-value, 90%)) !default;
$text-color-step-950: var(--ion-color-step-50, mix($background-color-value, $text-color-value, 95%)) !default;
$background-color-step-50: var(--ion-background-color-step-50, mix($text-color-value, $background-color-value, 5%)) !default;
$background-color-step-100: var(--ion-background-color-step-100, mix($text-color-value, $background-color-value, 10%)) !default;
$background-color-step-150: var(--ion-background-color-step-150, mix($text-color-value, $background-color-value, 15%)) !default;
$background-color-step-200: var(--ion-background-color-step-200, mix($text-color-value, $background-color-value, 20%)) !default;
$background-color-step-250: var(--ion-background-color-step-250, mix($text-color-value, $background-color-value, 25%)) !default;
$background-color-step-300: var(--ion-background-color-step-300, mix($text-color-value, $background-color-value, 30%)) !default;
$background-color-step-350: var(--ion-background-color-step-350, mix($text-color-value, $background-color-value, 35%)) !default;
$background-color-step-400: var(--ion-background-color-step-400, mix($text-color-value, $background-color-value, 40%)) !default;
$background-color-step-450: var(--ion-background-color-step-450, mix($text-color-value, $background-color-value, 45%)) !default;
$background-color-step-500: var(--ion-background-color-step-500, mix($text-color-value, $background-color-value, 50%)) !default;
$background-color-step-550: var(--ion-background-color-step-550, mix($text-color-value, $background-color-value, 55%)) !default;
$background-color-step-600: var(--ion-background-color-step-600, mix($text-color-value, $background-color-value, 60%)) !default;
$background-color-step-650: var(--ion-background-color-step-650, mix($text-color-value, $background-color-value, 65%)) !default;
$background-color-step-700: var(--ion-background-color-step-700, mix($text-color-value, $background-color-value, 70%)) !default;
$background-color-step-750: var(--ion-background-color-step-750, mix($text-color-value, $background-color-value, 75%)) !default;
$background-color-step-800: var(--ion-background-color-step-800, mix($text-color-value, $background-color-value, 80%)) !default;
$background-color-step-850: var(--ion-background-color-step-850, mix($text-color-value, $background-color-value, 85%)) !default;
$background-color-step-900: var(--ion-background-color-step-900, mix($text-color-value, $background-color-value, 90%)) !default;
$background-color-step-950: var(--ion-background-color-step-950, mix($text-color-value, $background-color-value, 95%)) !default;
$text-color-step-50: var(--ion-text-color-step-50, mix($background-color-value, $text-color-value, 5%)) !default;
$text-color-step-100: var(--ion-text-color-step-100, mix($background-color-value, $text-color-value, 10%)) !default;
$text-color-step-150: var(--ion-text-color-step-150, mix($background-color-value, $text-color-value, 15%)) !default;
$text-color-step-200: var(--ion-text-color-step-200, mix($background-color-value, $text-color-value, 20%)) !default;
$text-color-step-250: var(--ion-text-color-step-250, mix($background-color-value, $text-color-value, 25%)) !default;
$text-color-step-300: var(--ion-text-color-step-300, mix($background-color-value, $text-color-value, 30%)) !default;
$text-color-step-350: var(--ion-text-color-step-350, mix($background-color-value, $text-color-value, 35%)) !default;
$text-color-step-400: var(--ion-text-color-step-400, mix($background-color-value, $text-color-value, 40%)) !default;
$text-color-step-450: var(--ion-text-color-step-450, mix($background-color-value, $text-color-value, 45%)) !default;
$text-color-step-500: var(--ion-text-color-step-500, mix($background-color-value, $text-color-value, 50%)) !default;
$text-color-step-550: var(--ion-text-color-step-550, mix($background-color-value, $text-color-value, 55%)) !default;
$text-color-step-600: var(--ion-text-color-step-600, mix($background-color-value, $text-color-value, 60%)) !default;
$text-color-step-650: var(--ion-text-color-step-650, mix($background-color-value, $text-color-value, 65%)) !default;
$text-color-step-700: var(--ion-text-color-step-700, mix($background-color-value, $text-color-value, 70%)) !default;
$text-color-step-750: var(--ion-text-color-step-750, mix($background-color-value, $text-color-value, 75%)) !default;
$text-color-step-800: var(--ion-text-color-step-800, mix($background-color-value, $text-color-value, 80%)) !default;
$text-color-step-850: var(--ion-text-color-step-850, mix($background-color-value, $text-color-value, 85%)) !default;
$text-color-step-900: var(--ion-text-color-step-900, mix($background-color-value, $text-color-value, 90%)) !default;
$text-color-step-950: var(--ion-text-color-step-950, mix($background-color-value, $text-color-value, 95%)) !default;
// Default General Colors
// --------------------------------------------------

View File

@@ -243,5 +243,5 @@ export interface BlockerConfig {
disableScroll?: boolean;
}
const BACKDROP_NO_SCROLL = 'backdrop-no-scroll';
export const BACKDROP_NO_SCROLL = 'backdrop-no-scroll';
export const GESTURE_CONTROLLER = new GestureController();

View File

@@ -20,6 +20,7 @@ import type {
} from '../interface';
import { CoreDelegate } from './framework-delegate';
import { BACKDROP_NO_SCROLL } from './gesture/gesture-controller';
import { OVERLAY_BACK_BUTTON_PRIORITY } from './hardware-back-button';
import { addEventListener, componentOnReady, focusElement, getElementRoot, removeEventListener } from './helpers';
import { printIonWarning } from './logging';
@@ -471,6 +472,8 @@ export const present = async <OverlayPresentOptions>(
setRootAriaHidden(true);
document.body.classList.add(BACKDROP_NO_SCROLL);
overlay.presented = true;
overlay.willPresent.emit();
overlay.willPresentShorthand?.emit();
@@ -549,12 +552,15 @@ export const dismiss = async <OverlayDismissOptions>(
return false;
}
const lastOverlay = doc !== undefined && getPresentedOverlays(doc).length === 1;
/**
* If this is the last visible overlay then
* we want to re-add the root to the accessibility tree.
*/
if (doc !== undefined && getPresentedOverlays(doc).length === 1) {
if (lastOverlay) {
setRootAriaHidden(false);
document.body.classList.remove(BACKDROP_NO_SCROLL);
}
overlay.presented = false;
@@ -574,6 +580,7 @@ export const dismiss = async <OverlayDismissOptions>(
if (role !== GESTURE) {
await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
}
overlay.didDismiss.emit({ data, role });
overlay.didDismissShorthand?.emit({ data, role });

View File

@@ -0,0 +1,88 @@
import { newSpecPage } from '@stencil/core/testing';
import { Modal } from '../../../components/modal/modal';
describe('overlays: scroll blocking', () => {
it('should not block scroll when the overlay is created', async () => {
const page = await newSpecPage({
components: [Modal],
html: `
<ion-modal></ion-modal>
`,
});
const body = page.doc.querySelector('body')!;
expect(body).not.toHaveClass('backdrop-no-scroll');
});
it('should block scroll when the overlay is presented', async () => {
const page = await newSpecPage({
components: [Modal],
html: `
<ion-modal></ion-modal>
`,
});
const modal = page.body.querySelector('ion-modal')!;
const body = page.doc.querySelector('body')!;
await modal.present();
expect(body).toHaveClass('backdrop-no-scroll');
await modal.dismiss();
expect(body).not.toHaveClass('backdrop-no-scroll');
});
it('should not block scroll when the overlay is dismissed', async () => {
const page = await newSpecPage({
components: [Modal],
html: `
<ion-modal></ion-modal>
`,
});
const modal = page.body.querySelector('ion-modal')!;
const body = page.doc.querySelector('body')!;
await modal.present();
expect(body).toHaveClass('backdrop-no-scroll');
await modal.dismiss();
expect(body).not.toHaveClass('backdrop-no-scroll');
});
it('should not enable scroll until last overlay is dismissed', async () => {
const page = await newSpecPage({
components: [Modal],
html: `
<ion-modal id="one"></ion-modal>
<ion-modal id="two"></ion-modal>
`,
});
const modalOne = page.body.querySelector('#one')!;
const modalTwo = page.body.querySelector('#two')!;
const body = page.doc.querySelector('body')!;
await modalOne.present();
expect(body).toHaveClass('backdrop-no-scroll');
await modalTwo.present();
expect(body).toHaveClass('backdrop-no-scroll');
await modalOne.dismiss();
expect(body).toHaveClass('backdrop-no-scroll');
await modalTwo.dismiss();
expect(body).not.toHaveClass('backdrop-no-scroll');
});
});

View File

@@ -58,7 +58,6 @@ const getAngularOutputTargets = () => {
'ion-textarea',
'ion-searchbar',
'ion-datetime',
'ion-radio',
'ion-segment',
'ion-checkbox',
'ion-toggle',

View File

@@ -1,5 +1,4 @@
export * from './boolean-value-accessor';
export * from './numeric-value-accessor';
export * from './radio-value-accessor';
export * from './select-value-accessor';
export * from './text-value-accessor';

View File

@@ -1,29 +0,0 @@
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from '@ionic/angular/common';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'ion-radio',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: RadioValueAccessorDirective,
multi: true,
},
],
})
export class RadioValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionSelect', ['$event.target'])
_handleIonSelect(el: any): void {
/**
* The `el` type is any to access the `checked` state property
* that is not exposed on the type interface.
*/
this.handleValueChange(el, el.checked);
}
}

View File

@@ -1,7 +1,6 @@
// DIRECTIVES
export { BooleanValueAccessorDirective as BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
export { NumericValueAccessorDirective as NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accessor';
export { RadioValueAccessorDirective as RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
export { SelectValueAccessorDirective as SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
export { TextValueAccessorDirective as TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
export { IonTabs } from './directives/navigation/ion-tabs';

View File

@@ -7,7 +7,6 @@ import { appInitialize } from './app-initialize';
import {
BooleanValueAccessorDirective,
NumericValueAccessorDirective,
RadioValueAccessorDirective,
SelectValueAccessorDirective,
TextValueAccessorDirective,
} from './directives/control-value-accessors';
@@ -37,7 +36,6 @@ const DECLARATIONS = [
// ngModel accessors
BooleanValueAccessorDirective,
NumericValueAccessorDirective,
RadioValueAccessorDirective,
SelectValueAccessorDirective,
TextValueAccessorDirective,

View File

@@ -3,7 +3,6 @@ export * from './datetime';
export * from './icon';
export * from './input';
export * from './radio-group';
export * from './radio';
export * from './range';
export * from './searchbar';
export * from './segment';

View File

@@ -53,6 +53,7 @@ import { defineCustomElement as defineIonNavLink } from '@ionic/core/components/
import { defineCustomElement as defineIonNote } from '@ionic/core/components/ion-note.js';
import { defineCustomElement as defineIonPicker } from '@ionic/core/components/ion-picker.js';
import { defineCustomElement as defineIonProgressBar } from '@ionic/core/components/ion-progress-bar.js';
import { defineCustomElement as defineIonRadio } from '@ionic/core/components/ion-radio.js';
import { defineCustomElement as defineIonRefresher } from '@ionic/core/components/ion-refresher.js';
import { defineCustomElement as defineIonRefresherContent } from '@ionic/core/components/ion-refresher-content.js';
import { defineCustomElement as defineIonReorder } from '@ionic/core/components/ion-reorder.js';
@@ -1494,6 +1495,40 @@ export class IonProgressBar {
export declare interface IonProgressBar extends Components.IonProgressBar {}
@ProxyCmp({
defineCustomElementFn: defineIonRadio,
inputs: ['alignment', 'color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value']
})
@Component({
selector: 'ion-radio',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['alignment', 'color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value'],
standalone: true
})
export class IonRadio {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']);
}
}
export declare interface IonRadio extends Components.IonRadio {
/**
* Emitted when the radio button has focus.
*/
ionFocus: EventEmitter<CustomEvent<void>>;
/**
* Emitted when the radio button loses focus.
*/
ionBlur: EventEmitter<CustomEvent<void>>;
}
@ProxyCmp({
defineCustomElementFn: defineIonRefresher,
inputs: ['closeDuration', 'disabled', 'pullFactor', 'pullMax', 'pullMin', 'snapbackDuration'],

View File

@@ -1,76 +0,0 @@
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
HostListener,
Injector,
NgZone,
forwardRef,
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from '@ionic/angular/common';
import type { Components } from '@ionic/core/components';
import { defineCustomElement } from '@ionic/core/components/ion-radio.js';
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value'];
/**
* Pulling the provider into an object and using PURE works
* around an ng-packagr issue that causes
* components with multiple decorators and
* a provider to be re-assigned. This re-assignment
* is not supported by Webpack and causes treeshaking
* to not work on these kinds of components.
*/
const accessorProvider = {
provide: NG_VALUE_ACCESSOR,
useExisting: /*@__PURE__*/ forwardRef(() => IonRadio),
multi: true,
};
@ProxyCmp({
defineCustomElementFn: defineCustomElement,
inputs: RADIO_INPUTS,
})
@Component({
selector: 'ion-radio',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: RADIO_INPUTS,
providers: [accessorProvider],
standalone: true,
})
export class IonRadio extends ValueAccessor {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
super(injector, r);
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']);
}
@HostListener('ionSelect', ['$event.target'])
handleIonSelect(el: any): void {
/**
* The `el` type is any to access the `checked` state property
* that is not exposed on the type interface.
*/
this.handleValueChange(el, el.checked);
}
}
export declare interface IonRadio extends Components.IonRadio {
/**
* Emitted when the radio button has focus.
*/
ionFocus: EventEmitter<CustomEvent<void>>;
/**
* Emitted when the radio button loses focus.
*/
ionBlur: EventEmitter<CustomEvent<void>>;
}

View File

@@ -34,7 +34,6 @@ export {
IonInput,
IonIcon,
IonRadioGroup,
IonRadio,
IonRange,
IonSearchbar,
IonSegment,

View File

@@ -32,7 +32,8 @@ describe('Form', () => {
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: false
checkbox: false,
radio: null
});
});
@@ -59,7 +60,8 @@ describe('Form', () => {
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: false
checkbox: false,
radio: null
});
});
@@ -73,7 +75,8 @@ describe('Form', () => {
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: false
checkbox: false,
radio: null
});
});
@@ -87,7 +90,23 @@ describe('Form', () => {
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: true
checkbox: true,
radio: null
});
});
it('ion-radio should change', () => {
cy.get('ion-radio').click();
testData({
datetime: '2010-08-20',
select: null,
toggle: false,
input: '',
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: false,
radio: 'nes'
});
});
@@ -109,7 +128,8 @@ describe('Form', () => {
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: false
checkbox: false,
radio: null
});
cy.get('ion-checkbox').click();
testData({
@@ -120,7 +140,8 @@ describe('Form', () => {
input2: 'Default Value',
inputMin: 1,
inputMax: 1,
checkbox: true
checkbox: true,
radio: null
});
});
});

View File

@@ -5,6 +5,7 @@ describe('Inputs', () => {
it('should have default value', () => {
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', true);
cy.get('ion-radio-group').should('have.prop', 'value').and('equal', 'nes');
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', true);
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some text');
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '1994-03-15');
@@ -15,6 +16,7 @@ describe('Inputs', () => {
cy.get('#reset-button').click();
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', false);
cy.get('ion-radio-group').should('not.have.prop', 'value');
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', false);
/**
* The `value` property gets set to undefined
@@ -32,6 +34,7 @@ describe('Inputs', () => {
cy.get('#set-button').click();
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', true);
cy.get('ion-radio-group').should('have.prop', 'value').and('equal', 'nes');
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', true);
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some text');
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '1994-03-15');
@@ -42,6 +45,7 @@ describe('Inputs', () => {
cy.get('#reset-button').click();
cy.get('ion-checkbox#first-checkbox').click();
cy.get('ion-radio').first().click();
cy.get('ion-toggle').first().click();
cy.get('ion-input').eq(0).type('hola');
@@ -58,6 +62,7 @@ describe('Inputs', () => {
cy.get('ion-alert .alert-button:not(.alert-button-role-cancel)').click();
cy.get('#checkbox-note').should('have.text', 'true');
cy.get('#radio-note').should('have.text', 'nes');
cy.get('#toggle-note').should('have.text', 'true');
cy.get('#input-note').should('have.text', 'hola');
cy.get('#datetime-note').should('have.text', '1994-03-14');

View File

@@ -48,6 +48,12 @@
<ion-checkbox formControlName="checkbox"> Checkbox </ion-checkbox>
</ion-item>
<ion-item>
<ion-radio-group formControlName="radio">
<ion-radio value="nes">Radio</ion-radio>
</ion-radio-group>
</ion-item>
<ion-item>
<ion-label>Min</ion-label>
<ion-input formControlName="inputMin" type="number"></ion-input>

View File

@@ -20,7 +20,8 @@ export class FormComponent {
input2: ['Default Value'],
inputMin: [1, Validators.min(1)],
inputMax: [1, Validators.max(1)],
checkbox: [false]
checkbox: [false],
radio: [undefined]
}, {
updateOn: typeof (window as any) !== 'undefined' && window.location.hash === '#blur' ? 'blur' : 'change'
});
@@ -44,7 +45,8 @@ export class FormComponent {
toggle: true,
input: 'Some value',
input2: 'Another values',
checkbox: true
checkbox: true,
radio: 'nes'
});
}

View File

@@ -85,6 +85,20 @@
<ion-note slot="end">{{checkbox}}</ion-note>
</ion-item>
<ion-item>
<ion-radio-group value="nes" [(ngModel)]="radio" id="first-radio">
<ion-radio value="nes">Radio</ion-radio>
</ion-radio-group>
<ion-note slot="end" id="radio-note">{{radio}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-radio-group value="nes" [(ngModel)]="radio">
<ion-radio value="nes">Radio Mirror</ion-radio>
</ion-radio-group>
<ion-note slot="end">{{radio}}</ion-note>
</ion-item>
</ion-list>
<p>
<ion-button (click)="setValues()" id="set-button">Set values</ion-button>

View File

@@ -9,6 +9,7 @@ export class InputsComponent {
datetime? = '1994-03-15';
input? = 'some text';
checkbox = true;
radio? = 'nes';
toggle = true;
select? = 'nes';
changes = 0;
@@ -18,6 +19,7 @@ export class InputsComponent {
this.datetime = '1994-03-15';
this.input = 'some text';
this.checkbox = true;
this.radio = 'nes';
this.toggle = true;
this.select = 'nes';
}
@@ -27,6 +29,7 @@ export class InputsComponent {
this.datetime = undefined;
this.input = undefined;
this.checkbox = false;
this.radio = undefined;
this.toggle = false;
this.select = undefined;
}