diff --git a/BREAKING.md b/BREAKING.md index 2fbe586ea87..8c9943b9101 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -19,6 +19,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver - [Components](#version-9x-components) - [Input](#version-9x-input) - [Legacy Picker](#version-9x-legacy-picker) + - [Modal](#version-9x-modal) - [Router Outlet](#version-9x-router-outlet) - [Searchbar](#version-9x-searchbar) - [Select](#version-9x-select) @@ -73,6 +74,16 @@ The string form no longer behaves the same way. Because an HTML attribute coerce - Remove any usages of `pickerController`. If using React, remove any usages of the `useIonPicker` hook. These controller-based APIs have been removed. Use the inline picker component instead. - Remove any usages of the `PickerOptions`, `PickerButton`, `PickerColumn`, and `PickerColumnOption` type exports. These types were associated with the legacy picker and have been removed. +

Modal

+ +The `handleBehavior` property on `ion-modal` now defaults to `"cycle"` instead of `"none"`. For sheet modals that display a handle, this means the handle is now focusable and activating it (by click, keyboard, or screen reader) cycles the sheet through its available breakpoints. This matches the native iOS sheet behavior and keeps sheet modals operable for assistive technology users by default. + +Sheet modals that relied on the handle being inert should set `handleBehavior="none"` to restore the previous behavior: + +```html + +``` +

Router Outlet

`ion-router-outlet` now exposes a `swipeGesture` property that controls the swipe-to-go-back gesture per outlet. This property defaults to `true` in `"ios"` mode and `false` in `"md"` mode. diff --git a/core/api.txt b/core/api.txt index 2d581216db4..067b07e818c 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1167,7 +1167,7 @@ ion-modal,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefin ion-modal,prop,expandToScroll,boolean,true,false,false ion-modal,prop,focusTrap,boolean,true,false,false ion-modal,prop,handle,boolean | undefined,undefined,false,false -ion-modal,prop,handleBehavior,"cycle" | "none" | undefined,'none',false,false +ion-modal,prop,handleBehavior,"cycle" | "none" | undefined,'cycle',false,false ion-modal,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false ion-modal,prop,initialBreakpoint,number | undefined,undefined,false,false ion-modal,prop,isOpen,boolean,false,false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 0b7f6cc25f3..2d8a59f1903 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -2003,8 +2003,8 @@ export namespace Components { */ "handle"?: boolean; /** - * The interaction behavior for the sheet modal when the handle is pressed. Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). - * @default 'none' + * The interaction behavior for the sheet modal when the handle is pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). Set to `"cycle"` to make the handle focusable and let the sheet modal cycle between available breakpoints when pressed. This keeps the sheet operable with assistive technology. Set to `"none"` to make the handle purely decorative when pressed and removed from the tab order. Defaults to `"cycle"`. + * @default 'cycle' */ "handleBehavior"?: ModalHandleBehavior; /** @@ -7152,8 +7152,8 @@ declare namespace LocalJSX { */ "handle"?: boolean; /** - * The interaction behavior for the sheet modal when the handle is pressed. Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). - * @default 'none' + * The interaction behavior for the sheet modal when the handle is pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). Set to `"cycle"` to make the handle focusable and let the sheet modal cycle between available breakpoints when pressed. This keeps the sheet operable with assistive technology. Set to `"none"` to make the handle purely decorative when pressed and removed from the tab order. Defaults to `"cycle"`. + * @default 'cycle' */ "handleBehavior"?: ModalHandleBehavior; /** diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index 44a6c77fdbe..443fd892181 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -202,13 +202,20 @@ export class Modal implements ComponentInterface, OverlayInterface { /** * The interaction behavior for the sheet modal when the handle is pressed. * - * Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. - * Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. + * Handle behavior is unavailable when the `handle` property is set to + * `false` or when the `breakpoints` property is not set (using a + * fullscreen or card modal). * - * Handle behavior is unavailable when the `handle` property is set to `false` or - * when the `breakpoints` property is not set (using a fullscreen or card modal). + * Set to `"cycle"` to make the handle focusable and let the sheet modal + * cycle between available breakpoints when pressed. This keeps the sheet + * operable with assistive technology. + * + * Set to `"none"` to make the handle purely decorative when pressed and + * removed from the tab order. + * + * Defaults to `"cycle"`. */ - @Prop() handleBehavior?: ModalHandleBehavior = 'none'; + @Prop() handleBehavior?: ModalHandleBehavior = 'cycle'; /** * The component to display inside of the modal. diff --git a/core/src/components/modal/test/sheet/index.html b/core/src/components/modal/test/sheet/index.html index e9c05b0a494..91b735edad7 100644 --- a/core/src/components/modal/test/sheet/index.html +++ b/core/src/components/modal/test/sheet/index.html @@ -133,6 +133,12 @@ > Present Sheet Modal (HandleBehavior: Cycle) + diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts b/core/src/components/modal/test/sheet/modal.e2e.ts index 06f2f7f7a98..dd47cb4fb54 100644 --- a/core/src/components/modal/test/sheet/modal.e2e.ts +++ b/core/src/components/modal/test/sheet/modal.e2e.ts @@ -264,7 +264,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); const modal = page.locator('ion-modal'); - await page.click('#sheet-modal'); + await page.click('#handle-behavior-none-modal'); await ionModalDidPresent.next(); const handle = page.locator('ion-modal .modal-handle');