fix(menu): update location when dynamically changing side or doc dir (#27079)

## Pull request checklist

Please check if your PR fulfills the following requirements:
- [x] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been reviewed and added / updated if needed (for bug
fixes / features)
- Some docs updates need to be made in the `ionic-docs` repo, in a
separate PR. See the [contributing
guide](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#modifying-documentation)
for details.
- [x] Build (`npm run build`) was run locally and any changes were
pushed
- [x] Lint (`npm run lint`) has passed locally and any fixes were made
for failures


## Pull request type

Please check the type of change your PR introduces:
- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe): 


## What is the current behavior?

- When the document direction is dynamically changed, the menu does not
switch to the correct position. For example, `<ion-menu side='start'>`
will always be on the left side regardless of direction.
- When the side property is dynamically changed, the animation starts in
the middle of the screen instead of off screen.

Issue URL: resolves #25601 #19489 


## What is the new behavior?

- Animation is smooth regardless of side property or document direction
being dynamically change.
- Menu appears on the correct side based on document direction when
dynamically updated.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

## Other information

N/A

---------

Co-authored-by: ionitron <hi@ionicframework.com>
This commit is contained in:
Maria Hutt
2023-04-04 12:03:13 -07:00
committed by GitHub
parent 4e7424de03
commit a35886e71c
12 changed files with 67 additions and 15 deletions

View File

@ -37,7 +37,6 @@
.menu-inner {
@include position(0, auto, 0, 0);
@include transform(translateX(-9999px));
display: flex;
@ -62,21 +61,13 @@
:host(.menu-side-start) .menu-inner {
--ion-safe-area-right: 0px;
@include multi-dir() {
/* stylelint-disable property-disallowed-list */
right: auto;
left: 0;
}
@include position(0, auto, 0, 0);
}
:host(.menu-side-end) .menu-inner {
--ion-safe-area-left: 0px;
@include multi-dir() {
right: 0;
left: auto;
/* stylelint-enable property-disallowed-list */
}
@include position(0, 0, 0, auto);
}
ion-backdrop {

View File

@ -130,6 +130,11 @@ export class Menu implements ComponentInterface, MenuI {
@Watch('side')
protected sideChanged() {
this.isEndSide = isEnd(this.side);
/**
* Menu direction animation is calculated based on the document direction.
* If the document direction changes, we need to create a new animation.
*/
this.animation = undefined;
}
/**
@ -413,10 +418,16 @@ export class Menu implements ComponentInterface, MenuI {
// Menu swipe animation takes the menu's inner width as parameter,
// If `offsetWidth` changes, we need to create a new animation.
const width = this.menuInnerEl!.offsetWidth;
if (width === this.width && this.animation !== undefined) {
/**
* Menu direction animation is calculated based on the document direction.
* If the document direction changes, we need to create a new animation.
*/
const isEndSide = isEnd(this.side);
if (width === this.width && this.animation !== undefined && isEndSide === this.isEndSide) {
return;
}
this.width = width;
this.isEndSide = isEndSide;
// Destroy existing animation
if (this.animation) {
@ -703,7 +714,7 @@ export class Menu implements ComponentInterface, MenuI {
}
render() {
const { isEndSide, type, disabled, isPaneVisible, inheritedAttributes } = this;
const { type, disabled, isPaneVisible, inheritedAttributes, side } = this;
const mode = getIonMode(this);
return (
@ -714,8 +725,7 @@ export class Menu implements ComponentInterface, MenuI {
[mode]: true,
[`menu-type-${type}`]: true,
'menu-enabled': !disabled,
'menu-side-end': isEndSide,
'menu-side-start': !isEndSide,
[`menu-side-${side}`]: true,
'menu-pane-visible': isPaneVisible,
}}
>

View File

@ -74,6 +74,57 @@ test.describe('menu: basic', () => {
await expect(scrollTop).toBe(200);
});
test('should render on the correct side when side is changed dynamically', async ({ page, skip }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/25601',
});
skip.mode('ios', 'Dynamic side changes are not mode dependent');
const ionDidOpen = await page.spyOnEvent('ionDidOpen');
const ionDidClose = await page.spyOnEvent('ionDidClose');
await page.locator('[menu-id="start-menu"]').evaluate(async (el: HTMLIonMenuElement) => {
el.side = 'end';
});
await page.click('#open-start');
await ionDidOpen.next();
await expect(page).toHaveScreenshot(`menu-basic-side-toggled-${page.getSnapshotSettings()}.png`);
await page.locator('[menu-id="start-menu"]').evaluate(async (el: HTMLIonMenuElement) => {
await el.close();
});
await ionDidClose.next();
});
test('should render on the correct side when document direction is changed dynamically', async ({ page, skip }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/25601',
});
skip.rtl('Document direction is not dependent on initial load');
skip.mode('ios', 'Dynamic side changes are not mode dependent');
const ionDidOpen = await page.spyOnEvent('ionDidOpen');
const ionDidClose = await page.spyOnEvent('ionDidClose');
await page.evaluate(() => {
document.dir = 'rtl';
});
await page.click('#open-start');
await ionDidOpen.next();
await expect(page).toHaveScreenshot(`menu-basic-doc-dir-toggled-${page.getSnapshotSettings()}.png`);
await page.locator('[menu-id="start-menu"]').evaluate(async (el: HTMLIonMenuElement) => {
await el.close();
});
await ionDidClose.next();
});
});
async function testMenu(page: E2EPage, menu: Locator, menuId: string) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB