Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(title): add large iOS toolbar title (#19268)
Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
- Loading branch information
1 parent
d9610cd
commit 923312e
Showing
21 changed files
with
964 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,3 +25,7 @@ | |
.header-md[no-border]::after { | ||
display: none; | ||
} | ||
|
||
.header-collapse-md { | ||
display: none; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core'; | ||
import { Component, ComponentInterface, Element, Host, Prop, h, readTask, writeTask } from '@stencil/core'; | ||
|
||
import { getIonMode } from '../../global/ionic-global'; | ||
|
||
import { cloneElement, createHeaderIndex, handleContentScroll, handleToolbarIntersection, setHeaderActive } from './header.utils'; | ||
/** | ||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. | ||
*/ | ||
|
@@ -14,6 +15,17 @@ import { getIonMode } from '../../global/ionic-global'; | |
}) | ||
export class Header implements ComponentInterface { | ||
|
||
private scrollEl?: HTMLElement; | ||
private contentScrollCallback?: any; | ||
|
||
@Element() el!: HTMLElement; | ||
|
||
/** | ||
* If `true`, the header will collapse on scroll of the content. | ||
* Only applies in `ios` mode. | ||
*/ | ||
@Prop() collapse = false; | ||
|
||
/** | ||
* If `true`, the header will be translucent. | ||
* Only applies when the mode is `"ios"` and the device supports | ||
|
@@ -24,6 +36,76 @@ export class Header implements ComponentInterface { | |
*/ | ||
@Prop() translucent = false; | ||
|
||
async componentDidLoad() { | ||
// Determine if the header can collapse | ||
const canCollapse = (this.collapse && getIonMode(this) === 'ios') ? this.collapse : false; | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
const tabs = this.el.closest('ion-tabs'); | ||
const page = this.el.closest('ion-app,ion-page,.ion-page,page-inner'); | ||
const contentEl = tabs ? tabs.querySelector('ion-content') : page!.querySelector('ion-content'); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
if (canCollapse) { | ||
await this.setupCollapsableHeader(contentEl, (tabs) ? tabs : page!); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
} | ||
|
||
componentDidUnload() { | ||
if (this.scrollEl && this.contentScrollCallback) { | ||
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback); | ||
} | ||
} | ||
|
||
private async setupCollapsableHeader(contentEl: HTMLIonContentElement | null, pageEl: Element) { | ||
if (!contentEl) { console.error('ion-header requires a content to collapse, make sure there is an ion-content.'); } | ||
|
||
this.scrollEl = await contentEl!.getScrollElement(); | ||
This comment has been minimized.
Sorry, something went wrong.
manucorporat
Contributor
|
||
|
||
readTask(() => { | ||
const headers = pageEl.querySelectorAll('ion-header'); | ||
const mainHeader = Array.from(headers).find((header: any) => !header.collapse) as HTMLElement | undefined; | ||
|
||
if (!mainHeader || !this.scrollEl) { return; } | ||
|
||
const mainHeaderIndex = createHeaderIndex(mainHeader); | ||
const scrollHeaderIndex = createHeaderIndex(this.el); | ||
|
||
if (!mainHeaderIndex || !scrollHeaderIndex) { return; } | ||
|
||
setHeaderActive(mainHeaderIndex, false); | ||
|
||
// TODO: Find a better way to do this | ||
let remainingHeight = 0; | ||
for (let i = 1; i <= scrollHeaderIndex.toolbars.length - 1; i++) { | ||
remainingHeight += scrollHeaderIndex.toolbars[i].el.clientHeight; | ||
} | ||
|
||
/** | ||
* Handle interaction between toolbar collapse and | ||
* showing/hiding content in the primary ion-header | ||
*/ | ||
const toolbarIntersection = (ev: any) => { handleToolbarIntersection(ev, mainHeaderIndex, scrollHeaderIndex); }; | ||
|
||
readTask(() => { | ||
const mainHeaderHeight = mainHeaderIndex.el.clientHeight; | ||
const intersectionObserver = new IntersectionObserver(toolbarIntersection, { threshold: 0.25, rootMargin: `-${mainHeaderHeight}px 0px 0px 0px` }); | ||
intersectionObserver.observe(scrollHeaderIndex.toolbars[0].el); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
}); | ||
|
||
/** | ||
* Handle scaling of large iOS titles and | ||
* showing/hiding border on last toolbar | ||
* in primary header | ||
*/ | ||
this.contentScrollCallback = () => { handleContentScroll(this.scrollEl!, mainHeaderIndex, scrollHeaderIndex, remainingHeight); }; | ||
this.scrollEl.addEventListener('scroll', this.contentScrollCallback); | ||
}); | ||
|
||
writeTask(() => { | ||
cloneElement('ion-title'); | ||
cloneElement('ion-back-button'); | ||
}); | ||
} | ||
|
||
render() { | ||
const mode = getIonMode(this); | ||
return ( | ||
|
@@ -36,6 +118,7 @@ export class Header implements ComponentInterface { | |
[`header-${mode}`]: true, | ||
|
||
[`header-translucent`]: this.translucent, | ||
[`header-collapse-${mode}`]: this.collapse, | ||
[`header-translucent-${mode}`]: this.translucent, | ||
}} | ||
> | ||
|
Oops, something went wrong.
some concerns about this API, it might be the correct one, but we should discuss more