Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(header): avoid flicker on collapsible header load #19682

Merged
merged 2 commits into from Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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