Skip to content

Commit

Permalink
fix(header): avoid flicker on collapsible header load (#19682)
Browse files Browse the repository at this point in the history
* fix flicker on collapse load

* remove old test
  • Loading branch information
liamdebeasi committed Oct 29, 2019
1 parent 39fb8f6 commit 0a7aae2
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 24 deletions.
4 changes: 2 additions & 2 deletions core/src/components/header/header.ios.scss
Expand Up @@ -51,8 +51,8 @@
padding-bottom: 13px;
}

ion-toolbar.in-toolbar ion-title,
ion-toolbar.in-toolbar ion-buttons {
.header-collapse-main ion-toolbar.in-toolbar ion-title,
.header-collapse-main ion-toolbar.in-toolbar ion-buttons {
transition: all 0.2s ease-in-out;
}

Expand Down
33 changes: 20 additions & 13 deletions core/src/components/header/header.tsx
Expand Up @@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Host, Prop, h, readTask, writeT

import { getIonMode } from '../../global/ionic-global';

import { cloneElement, createHeaderIndex, handleContentScroll, handleToolbarIntersection, setHeaderActive } from './header.utils';
import { cloneElement, createHeaderIndex, handleContentScroll, handleToolbarIntersection, setHeaderActive, setToolbarBackgroundOpacity } from './header.utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
Expand All @@ -19,6 +19,7 @@ export class Header implements ComponentInterface {
private scrollEl?: HTMLElement;
private contentScrollCallback?: any;
private intersectionObserver?: any;
private collapsibleMainHeader?: HTMLElement;

@Element() el!: HTMLElement;

Expand Down Expand Up @@ -77,27 +78,32 @@ export class Header implements ComponentInterface {
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
this.contentScrollCallback = undefined;
}

if (this.collapsibleMainHeader) {
this.collapsibleMainHeader.classList.remove('header-collapse-main');
this.collapsibleMainHeader = undefined;
}
}

private async setupCollapsibleHeader(contentEl: HTMLIonContentElement | null, pageEl: Element | null) {
if (!contentEl || !pageEl) { console.error('ion-header requires a content to collapse, make sure there is an ion-content.'); return; }

this.scrollEl = await contentEl.getScrollElement();

readTask(() => {
const headers = pageEl.querySelectorAll('ion-header');
const mainHeader = Array.from(headers).find((header: any) => header.collapse !== 'condense') as HTMLElement | undefined;
const headers = pageEl.querySelectorAll('ion-header');
this.collapsibleMainHeader = Array.from(headers).find((header: any) => header.collapse !== 'condense') as HTMLElement | undefined;

if (!mainHeader || !this.scrollEl) { return; }
if (!this.collapsibleMainHeader) { return; }

const mainHeaderIndex = createHeaderIndex(mainHeader);
const scrollHeaderIndex = createHeaderIndex(this.el);
const mainHeaderIndex = createHeaderIndex(this.collapsibleMainHeader);
const scrollHeaderIndex = createHeaderIndex(this.el);

if (!mainHeaderIndex || !scrollHeaderIndex) { return; }
if (!mainHeaderIndex || !scrollHeaderIndex) { return; }

setHeaderActive(mainHeaderIndex, false);
setHeaderActive(mainHeaderIndex, false);
setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0], 0);

readTask(() => {
readTask(() => {
const mainHeaderHeight = mainHeaderIndex.el.clientHeight;

/**
Expand All @@ -109,20 +115,21 @@ export class Header implements ComponentInterface {
const toolbarIntersection = (ev: any) => { handleToolbarIntersection(ev, mainHeaderIndex, scrollHeaderIndex); };
this.intersectionObserver = new IntersectionObserver(toolbarIntersection, { threshold: [0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], rootMargin: `-${mainHeaderHeight}px 0px 0px 0px` });
this.intersectionObserver.observe(scrollHeaderIndex.toolbars[0].el);
});

/**
* Handle scaling of large iOS titles and
* showing/hiding border on last toolbar
* in primary header
*/
this.contentScrollCallback = () => { handleContentScroll(this.scrollEl!, scrollHeaderIndex); };
this.scrollEl.addEventListener('scroll', this.contentScrollCallback);
this.contentScrollCallback = () => { handleContentScroll(this.scrollEl!, scrollHeaderIndex); };
this.scrollEl!.addEventListener('scroll', this.contentScrollCallback);
});

writeTask(() => {
cloneElement('ion-title');
cloneElement('ion-back-button');

this.collapsibleMainHeader!.classList.add('header-collapse-main');
});

this.collapsibleHeaderInitialized = true;
Expand Down
16 changes: 7 additions & 9 deletions core/src/components/header/header.utils.ts
Expand Up @@ -45,7 +45,7 @@ export const createHeaderIndex = (headerEl: HTMLElement | undefined): HeaderInde
innerTitleEl: (ionTitleEl) ? ionTitleEl.shadowRoot!.querySelector('.toolbar-title') : null,
ionButtonsEl: Array.from(toolbar.querySelectorAll('ion-buttons')) || []
} as ToolbarIndex;
}) || [[]]
}) || []
} as HeaderIndex;
};

Expand All @@ -60,7 +60,7 @@ export const handleContentScroll = (scrollEl: HTMLElement, scrollHeaderIndex: He
});
};

const setToolbarBackgroundOpacity = (toolbar: ToolbarIndex, opacity: number | undefined) => {
export const setToolbarBackgroundOpacity = (toolbar: ToolbarIndex, opacity: number | undefined) => {
if (opacity === undefined) {
toolbar.background.style.removeProperty('--opacity');
} else {
Expand Down Expand Up @@ -124,13 +124,11 @@ export const handleToolbarIntersection = (ev: any, mainHeaderIndex: HeaderIndex,
};

export const setHeaderActive = (headerIndex: HeaderIndex, active = true) => {
writeTask(() => {
if (active) {
headerIndex.el.classList.remove('header-collapse-condense-inactive');
} else {
headerIndex.el.classList.add('header-collapse-condense-inactive');
}
});
if (active) {
headerIndex.el.classList.remove('header-collapse-condense-inactive');
} else {
headerIndex.el.classList.add('header-collapse-condense-inactive');
}
};

export const scaleLargeTitles = (toolbars: ToolbarIndex[] = [], scale = 1, transition = false) => {
Expand Down

0 comments on commit 0a7aae2

Please sign in to comment.