ionic-header-parallax
Advanced tools
Comparing version 3.0.0-dev to 3.0.2
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : | ||
typeof define === 'function' && define.amd ? define('ionic-header-parallax', ['exports', '@angular/core'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['ionic-header-parallax'] = {}, global.ng.core)); | ||
}(this, (function (exports, i0) { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@ionic/angular')) : | ||
typeof define === 'function' && define.amd ? define('ionic-header-parallax', ['exports', '@angular/core', '@ionic/angular'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['ionic-header-parallax'] = {}, global.ng.core, global.angular)); | ||
}(this, (function (exports, i0, angular) { 'use strict'; | ||
@@ -33,190 +33,140 @@ function _interopNamespace(e) { | ||
this.renderer = renderer; | ||
this.maximumHeight = 300; | ||
this.height = 300; | ||
this.bgPosition = 'top'; | ||
this.originalToolbarHeight = 0; | ||
this.ticking = false; | ||
} | ||
ParallaxDirective.prototype.ngAfterViewInit = function () { | ||
ParallaxDirective.prototype.ngAfterContentInit = function () { | ||
var _this = this; | ||
setTimeout(function () { | ||
try { | ||
_this.initElements(); | ||
_this.initStyles(); | ||
_this.initEvents(); | ||
if (_this.initElements()) { | ||
_this.setupContentPadding(); | ||
_this.setupImageOverlay(); | ||
_this.setupEvents(); | ||
_this.updateProgress(); | ||
} | ||
} | ||
catch (e) { | ||
_this.ngAfterViewInit(); | ||
_this.ngAfterContentInit(); | ||
} | ||
}, 100); | ||
}; | ||
Object.defineProperty(ParallaxDirective.prototype, "header", { | ||
get: function () { | ||
return this.headerRef.nativeElement; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
/** | ||
* Return the value of the input parameter `height` as a string with units. | ||
* If no units were provided, it will default to 'px'. | ||
*/ | ||
ParallaxDirective.prototype.getMaxHeightWithUnits = function () { | ||
return !isNaN(+this.height) || typeof this.height === 'number' | ||
? this.height + 'px' | ||
: this.height; | ||
}; | ||
ParallaxDirective.prototype.initElements = function () { | ||
var _this = this; | ||
var parentElement = this.headerRef.nativeElement.parentElement; | ||
this.header = this.headerRef.nativeElement; | ||
this.toolbar = this.header.querySelector('ion-toolbar'); | ||
if (!this.toolbar) { | ||
throw new Error('Parallax directive requires a toolbar or navbar element on the page to work.'); | ||
if (!this.ionToolbar) { | ||
console.error('A <ion-toolbar> element is needed inside <ion-header>'); | ||
return false; | ||
} | ||
this.ionTitle = this.toolbar.querySelector('ion-title'); | ||
this.toolbarBackground = this.toolbar.shadowRoot.querySelector('.toolbar-background'); | ||
this.barButtons = this.headerRef.nativeElement.querySelector('ion-buttons'); | ||
var parentElement = this.header.parentElement; | ||
var ionContent = parentElement.querySelector('ion-content'); | ||
this.scrollContent = ionContent.shadowRoot.querySelector('.inner-scroll'); | ||
if (!this.scrollContent) { | ||
throw new Error('Parallax directive requires an <ion-content> element on the page to work.'); | ||
if (!ionContent) { | ||
console.error('A <ion-content> element is needed'); | ||
return false; | ||
} | ||
// Create image overlay | ||
this.innerScroll = ionContent.shadowRoot.querySelector('.inner-scroll'); | ||
this.originalToolbarHeight = this.ionToolbar.el.offsetHeight; | ||
this.toolbarContainer = | ||
this.ionToolbar.el.shadowRoot.querySelector('.toolbar-container'); | ||
this.toolbarBackground = this.ionToolbar.el.shadowRoot.querySelector('.toolbar-background'); | ||
this.color = this.color || window.getComputedStyle(this.toolbarBackground).backgroundColor; | ||
this.renderer.setStyle(this.header, 'pointer-events', 'none'); | ||
this.renderer.setStyle(this.toolbarContainer, 'pointer-events', 'all'); | ||
this.renderer.setStyle(this.toolbarContainer, 'align-items', 'baseline'); | ||
return true; | ||
}; | ||
ParallaxDirective.prototype.setupContentPadding = function () { | ||
var parentElement = this.header.parentElement; | ||
var ionContent = parentElement.querySelector('ion-content'); | ||
var mainContent = ionContent.shadowRoot.querySelector('main'); | ||
var paddingTop = window.getComputedStyle(mainContent).paddingTop; | ||
var calc = "calc(" + paddingTop + " + " + this.getMaxHeightWithUnits() + ")"; | ||
this.renderer.setStyle(this.header, 'position', 'absolute'); | ||
this.renderer.setStyle(this.innerScroll, 'padding-top', calc); | ||
}; | ||
ParallaxDirective.prototype.setupImageOverlay = function () { | ||
this.imageOverlay = this.renderer.createElement('div'); | ||
this.renderer.addClass(this.imageOverlay, 'image-overlay'); | ||
this.colorOverlay = this.renderer.createElement('div'); | ||
this.renderer.addClass(this.colorOverlay, 'color-overlay'); | ||
this.colorOverlay.appendChild(this.imageOverlay); | ||
this.header.appendChild(this.colorOverlay); | ||
// Copy title and buttons | ||
this.overlayTitle = this.ionTitle && this.ionTitle.cloneNode(true); | ||
if (this.overlayTitle) { | ||
this.renderer.addClass(this.overlayTitle, 'parallax-title'); | ||
setTimeout(function () { | ||
var toolbarTitle = _this.overlayTitle.shadowRoot.querySelector('.toolbar-title'); | ||
_this.renderer.setStyle(toolbarTitle, 'pointer-events', 'unset'); | ||
}); | ||
} | ||
if (this.overlayTitle) { | ||
this.imageOverlay.appendChild(this.overlayTitle); | ||
} | ||
if (this.barButtons) { | ||
this.imageOverlay.appendChild(this.barButtons); | ||
} | ||
}; | ||
ParallaxDirective.prototype.initStyles = function () { | ||
var _this = this; | ||
this.headerHeight = this.scrollContent.clientHeight; | ||
this.ticking = false; | ||
if (!this.scrollContent || !toolbar) { | ||
return; | ||
} | ||
// fetch styles | ||
this.maximumHeight = parseFloat(this.maximumHeight.toString()); | ||
this.headerMinHeight = this.toolbar.offsetHeight; | ||
this.scrollContentPaddingTop = window.getComputedStyle(this.scrollContent, null).paddingTop.replace('px', ''); | ||
this.scrollContentPaddingTop = parseFloat(this.scrollContentPaddingTop); | ||
this.originalToolbarBgColor = window.getComputedStyle(this.toolbarBackground, null).backgroundColor; | ||
if (!this.originalToolbarBgColor) { | ||
throw new Error('Error: toolbarBackround is null.'); | ||
} | ||
// header and title | ||
this.renderer.setStyle(this.header, 'position', 'relative'); | ||
if (this.overlayTitle) { | ||
this.renderer.setStyle(this.overlayTitle, 'color', this.titleColor); | ||
this.renderer.setStyle(this.overlayTitle, 'position', 'absolute'); | ||
this.renderer.setStyle(this.overlayTitle, 'width', '100%'); | ||
this.renderer.setStyle(this.overlayTitle, 'height', '100%'); | ||
this.renderer.setStyle(this.overlayTitle, 'text-align', 'center'); | ||
} | ||
// color overlay | ||
this.renderer.setStyle(this.colorOverlay, 'background-color', this.originalToolbarBgColor); | ||
this.renderer.setStyle(this.colorOverlay, 'height', this.maximumHeight + "px"); | ||
this.renderer.setStyle(this.colorOverlay, 'position', 'absolute'); | ||
this.renderer.setStyle(this.colorOverlay, 'top', -this.headerMinHeight * 0 + "px"); | ||
this.renderer.setStyle(this.colorOverlay, 'left', '0'); | ||
this.renderer.setStyle(this.colorOverlay, 'width', '100%'); | ||
this.renderer.setStyle(this.colorOverlay, 'z-index', '10'); | ||
this.renderer.setStyle(this.colorOverlay, 'pointer-events', 'none'); | ||
// image overlay | ||
this.renderer.setStyle(this.imageOverlay, 'background-color', this.expandedColor); | ||
this.renderer.setStyle(this.imageOverlay, 'background-color', this.color); | ||
this.renderer.setStyle(this.imageOverlay, 'background-image', "url(" + (this.imageUrl || '') + ")"); | ||
this.renderer.setStyle(this.imageOverlay, 'height', "100%"); | ||
this.renderer.setStyle(this.imageOverlay, 'width', '100%'); | ||
this.renderer.setStyle(this.imageOverlay, 'pointer-events', 'none'); | ||
this.renderer.setStyle(this.imageOverlay, 'background-size', 'cover'); | ||
this.renderer.setStyle(this.imageOverlay, 'background-position', 'center'); | ||
// .toolbar-background | ||
this.renderer.setStyle(this.toolbarBackground, 'background-color', this.originalToolbarBgColor); | ||
// .bar-buttons | ||
if (this.barButtons) { | ||
this.renderer.setStyle(this.barButtons, 'pointer-events', 'all'); | ||
Array.from(this.barButtons.children).forEach(function (btn) { | ||
_this.renderer.setStyle(btn, 'color', _this.titleColor); | ||
}); | ||
} | ||
// .scroll-content | ||
if (this.scrollContent) { | ||
this.renderer.setAttribute(this.scrollContent, 'parallax', ''); | ||
this.renderer.setStyle(this.scrollContent, 'padding-top', this.maximumHeight + this.scrollContentPaddingTop - this.headerMinHeight + "px"); | ||
} | ||
this.renderer.setStyle(this.imageOverlay, 'background-position', this.bgPosition); | ||
this.toolbarBackground.appendChild(this.imageOverlay); | ||
}; | ||
ParallaxDirective.prototype.initEvents = function () { | ||
ParallaxDirective.prototype.setupEvents = function () { | ||
var _this = this; | ||
window.addEventListener('resize', function () { | ||
_this.headerHeight = _this.scrollContent.clientHeight; | ||
}, false); | ||
if (this.scrollContent) { | ||
this.scrollContent.addEventListener('scroll', function (e) { | ||
if (!_this.ticking) { | ||
window.requestAnimationFrame(function () { | ||
_this.updateElasticHeader(); | ||
}); | ||
} | ||
_this.ticking = true; | ||
}); | ||
} | ||
}; | ||
ParallaxDirective.prototype.updateElasticHeader = function () { | ||
var _this = this; | ||
if (!this.scrollContent || !toolbar) { | ||
return; | ||
} | ||
this.scrollTop = this.scrollContent.scrollTop; | ||
if (this.scrollTop >= 0) { | ||
this.translateAmt = this.scrollTop / 2; | ||
this.scaleAmt = 1; | ||
} | ||
else { | ||
this.translateAmt = 0; | ||
this.scaleAmt = -this.scrollTop / this.headerHeight + 1; | ||
} | ||
// Parallax total progress | ||
this.headerMinHeight = this.toolbar.offsetHeight; | ||
var progress = (this.maximumHeight - this.scrollTop - this.headerMinHeight) / (this.maximumHeight - this.headerMinHeight); | ||
progress = Math.max(progress, 0); | ||
// ion-header: set height | ||
var targetHeight = this.maximumHeight - this.scrollTop; | ||
targetHeight = Math.max(targetHeight, this.headerMinHeight); | ||
// .toolbar-background: change color | ||
this.renderer.setStyle(this.imageOverlay, 'height', targetHeight + "px"); | ||
this.renderer.setStyle(this.imageOverlay, 'opacity', "" + progress); | ||
this.renderer.setStyle(this.colorOverlay, 'height', targetHeight + "px"); | ||
this.renderer.setStyle(this.colorOverlay, 'opacity', targetHeight > this.headerMinHeight ? '1' : '0'); | ||
this.renderer.setStyle(this.toolbarBackground, 'background-color', targetHeight > this.headerMinHeight ? 'transparent' : this.originalToolbarBgColor); | ||
// .bar-buttons | ||
if (this.barButtons) { | ||
if (targetHeight > this.headerMinHeight) { | ||
this.imageOverlay.append(this.barButtons); | ||
Array.from(this.barButtons.children).forEach(function (btn) { | ||
_this.renderer.setStyle(btn, 'color', _this.titleColor); | ||
this.innerScroll.addEventListener('scroll', function (_event) { | ||
if (!_this.ticking) { | ||
window.requestAnimationFrame(function () { | ||
_this.updateProgress(); | ||
_this.ticking = false; | ||
}); | ||
} | ||
else { | ||
this.toolbar.append(this.barButtons); | ||
Array.from(this.barButtons.children).forEach(function (btn) { | ||
_this.renderer.setStyle(btn, 'color', 'unset'); | ||
}); | ||
} | ||
} | ||
this.ticking = false; | ||
_this.ticking = true; | ||
}); | ||
}; | ||
/** Update the parallax effect as per the current scroll of the ion-content */ | ||
ParallaxDirective.prototype.updateProgress = function () { | ||
var progress = this.calcProgress(this.innerScroll, +this.height); | ||
this.progressLayerHeight(progress); | ||
this.progressLayerOpacity(progress); | ||
}; | ||
ParallaxDirective.prototype.progressLayerHeight = function (progress) { | ||
var h = Math.max(+this.height * (1 - progress), this.originalToolbarHeight); | ||
this.renderer.setStyle(this.toolbarContainer, 'height', h + "px"); | ||
this.renderer.setStyle(this.imageOverlay, 'height', h + "px"); | ||
}; | ||
ParallaxDirective.prototype.progressLayerOpacity = function (progress) { | ||
var op = 1 - progress; | ||
this.renderer.setStyle(this.imageOverlay, 'opacity', op); | ||
// this.renderer.setStyle(this.toolbarContainer, 'opacity', progress); | ||
}; | ||
ParallaxDirective.prototype.calcProgress = function (scrollingElement, maxHeight) { | ||
var scroll = +scrollingElement.scrollTop; | ||
var progress = Math.min(1, Math.max(0, scroll / maxHeight)); | ||
return progress; | ||
}; | ||
return ParallaxDirective; | ||
}()); | ||
ParallaxDirective.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.2", ngImport: i0__namespace, type: ParallaxDirective, deps: [{ token: i0__namespace.ElementRef }, { token: i0__namespace.Renderer2 }], target: i0__namespace.ɵɵFactoryTarget.Directive }); | ||
ParallaxDirective.ɵdir = i0__namespace.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.0.2", type: ParallaxDirective, selector: "ion-header[parallax]", inputs: { imageUrl: "imageUrl", expandedColor: "expandedColor", titleColor: "titleColor", maximumHeight: "maximumHeight" }, ngImport: i0__namespace }); | ||
ParallaxDirective.ɵdir = i0__namespace.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.0.2", type: ParallaxDirective, selector: "ion-header[parallax]", inputs: { imageUrl: "imageUrl", color: "color", height: "height", bgPosition: "bgPosition" }, queries: [{ propertyName: "ionTitle", first: true, predicate: angular.IonTitle, descendants: true }, { propertyName: "ionToolbar", first: true, predicate: angular.IonToolbar, descendants: true }, { propertyName: "ionButtons", predicate: angular.IonButtons }], ngImport: i0__namespace }); | ||
i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.2", ngImport: i0__namespace, type: ParallaxDirective, decorators: [{ | ||
type: i0.Directive, | ||
args: [{ | ||
selector: 'ion-header[parallax]' | ||
selector: 'ion-header[parallax]', | ||
}] | ||
}], ctorParameters: function () { return [{ type: i0__namespace.ElementRef }, { type: i0__namespace.Renderer2 }]; }, propDecorators: { imageUrl: [{ | ||
type: i0.Input | ||
}], expandedColor: [{ | ||
}], color: [{ | ||
type: i0.Input | ||
}], titleColor: [{ | ||
}], height: [{ | ||
type: i0.Input | ||
}], maximumHeight: [{ | ||
}], bgPosition: [{ | ||
type: i0.Input | ||
}], ionTitle: [{ | ||
type: i0.ContentChild, | ||
args: [angular.IonTitle, { static: false }] | ||
}], ionToolbar: [{ | ||
type: i0.ContentChild, | ||
args: [angular.IonToolbar, { static: false }] | ||
}], ionButtons: [{ | ||
type: i0.ContentChildren, | ||
args: [angular.IonButtons] | ||
}] } }); | ||
@@ -223,0 +173,0 @@ |
import { NgModule } from '@angular/core'; | ||
import { ParallaxDirective } from './parallax.directive'; | ||
import { ParallaxDirective } from './ionic-header-parallax.directive'; | ||
import * as i0 from "@angular/core"; | ||
@@ -21,2 +21,2 @@ export class IonicHeaderParallaxModule { | ||
}] }); | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW9uaWMtaGVhZGVyLXBhcmFsbGF4Lm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2lvbmljLWhlYWRlci1wYXJhbGxheC9zcmMvbGliL2lvbmljLWhlYWRlci1wYXJhbGxheC5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7QUFZekQsTUFBTSxPQUFPLHlCQUF5Qjs7c0hBQXpCLHlCQUF5Qjt1SEFBekIseUJBQXlCLGlCQVJsQyxpQkFBaUIsYUFLakIsaUJBQWlCO3VIQUdSLHlCQUF5QixZQU4zQixFQUNSOzJGQUtVLHlCQUF5QjtrQkFWckMsUUFBUTttQkFBQztvQkFDUixZQUFZLEVBQUU7d0JBQ1osaUJBQWlCO3FCQUNsQjtvQkFDRCxPQUFPLEVBQUUsRUFDUjtvQkFDRCxPQUFPLEVBQUU7d0JBQ1AsaUJBQWlCO3FCQUNsQjtpQkFDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQYXJhbGxheERpcmVjdGl2ZSB9IGZyb20gJy4vcGFyYWxsYXguZGlyZWN0aXZlJztcblxuQE5nTW9kdWxlKHtcbiAgZGVjbGFyYXRpb25zOiBbXG4gICAgUGFyYWxsYXhEaXJlY3RpdmVcbiAgXSxcbiAgaW1wb3J0czogW1xuICBdLFxuICBleHBvcnRzOiBbXG4gICAgUGFyYWxsYXhEaXJlY3RpdmVcbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBJb25pY0hlYWRlclBhcmFsbGF4TW9kdWxlIHsgfVxuIl19 | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW9uaWMtaGVhZGVyLXBhcmFsbGF4Lm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2lvbmljLWhlYWRlci1wYXJhbGxheC9zcmMvbGliL2lvbmljLWhlYWRlci1wYXJhbGxheC5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQzs7QUFZdEUsTUFBTSxPQUFPLHlCQUF5Qjs7c0hBQXpCLHlCQUF5Qjt1SEFBekIseUJBQXlCLGlCQVJsQyxpQkFBaUIsYUFLakIsaUJBQWlCO3VIQUdSLHlCQUF5QixZQU4zQixFQUNSOzJGQUtVLHlCQUF5QjtrQkFWckMsUUFBUTttQkFBQztvQkFDUixZQUFZLEVBQUU7d0JBQ1osaUJBQWlCO3FCQUNsQjtvQkFDRCxPQUFPLEVBQUUsRUFDUjtvQkFDRCxPQUFPLEVBQUU7d0JBQ1AsaUJBQWlCO3FCQUNsQjtpQkFDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQYXJhbGxheERpcmVjdGl2ZSB9IGZyb20gJy4vaW9uaWMtaGVhZGVyLXBhcmFsbGF4LmRpcmVjdGl2ZSc7XG5cbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW1xuICAgIFBhcmFsbGF4RGlyZWN0aXZlXG4gIF0sXG4gIGltcG9ydHM6IFtcbiAgXSxcbiAgZXhwb3J0czogW1xuICAgIFBhcmFsbGF4RGlyZWN0aXZlXG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgSW9uaWNIZWFkZXJQYXJhbGxheE1vZHVsZSB7IH1cbiJdfQ== |
/* | ||
* Public API Surface of ionic-header-parallax | ||
*/ | ||
export * from './lib/ionic-header-parallax.directive'; | ||
export * from './lib/ionic-header-parallax.module'; | ||
export * from './lib/parallax.directive'; | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2lvbmljLWhlYWRlci1wYXJhbGxheC9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsb0NBQW9DLENBQUM7QUFDbkQsY0FBYywwQkFBMEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2YgaW9uaWMtaGVhZGVyLXBhcmFsbGF4XG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvaW9uaWMtaGVhZGVyLXBhcmFsbGF4Lm1vZHVsZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9wYXJhbGxheC5kaXJlY3RpdmUnOyJdfQ== | ||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2lvbmljLWhlYWRlci1wYXJhbGxheC9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsdUNBQXVDLENBQUM7QUFDdEQsY0FBYyxvQ0FBb0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2YgaW9uaWMtaGVhZGVyLXBhcmFsbGF4XG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvaW9uaWMtaGVhZGVyLXBhcmFsbGF4LmRpcmVjdGl2ZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9pb25pYy1oZWFkZXItcGFyYWxsYXgubW9kdWxlJztcbiJdfQ== |
import * as i0 from '@angular/core'; | ||
import { Directive, Input, NgModule } from '@angular/core'; | ||
import { Directive, Input, ContentChild, ContentChildren, NgModule } from '@angular/core'; | ||
import { IonTitle, IonToolbar, IonButtons } from '@ionic/angular'; | ||
@@ -8,184 +9,133 @@ class ParallaxDirective { | ||
this.renderer = renderer; | ||
this.maximumHeight = 300; | ||
this.height = 300; | ||
this.bgPosition = 'top'; | ||
this.originalToolbarHeight = 0; | ||
this.ticking = false; | ||
} | ||
ngAfterViewInit() { | ||
ngAfterContentInit() { | ||
setTimeout(() => { | ||
try { | ||
this.initElements(); | ||
this.initStyles(); | ||
this.initEvents(); | ||
if (this.initElements()) { | ||
this.setupContentPadding(); | ||
this.setupImageOverlay(); | ||
this.setupEvents(); | ||
this.updateProgress(); | ||
} | ||
} | ||
catch (e) { | ||
this.ngAfterViewInit(); | ||
this.ngAfterContentInit(); | ||
} | ||
}, 100); | ||
} | ||
get header() { | ||
return this.headerRef.nativeElement; | ||
} | ||
/** | ||
* Return the value of the input parameter `height` as a string with units. | ||
* If no units were provided, it will default to 'px'. | ||
*/ | ||
getMaxHeightWithUnits() { | ||
return !isNaN(+this.height) || typeof this.height === 'number' | ||
? this.height + 'px' | ||
: this.height; | ||
} | ||
initElements() { | ||
const parentElement = this.headerRef.nativeElement.parentElement; | ||
this.header = this.headerRef.nativeElement; | ||
this.toolbar = this.header.querySelector('ion-toolbar'); | ||
if (!this.toolbar) { | ||
throw new Error('Parallax directive requires a toolbar or navbar element on the page to work.'); | ||
if (!this.ionToolbar) { | ||
console.error('A <ion-toolbar> element is needed inside <ion-header>'); | ||
return false; | ||
} | ||
this.ionTitle = this.toolbar.querySelector('ion-title'); | ||
this.toolbarBackground = this.toolbar.shadowRoot.querySelector('.toolbar-background'); | ||
this.barButtons = this.headerRef.nativeElement.querySelector('ion-buttons'); | ||
const parentElement = this.header.parentElement; | ||
const ionContent = parentElement.querySelector('ion-content'); | ||
this.scrollContent = ionContent.shadowRoot.querySelector('.inner-scroll'); | ||
if (!this.scrollContent) { | ||
throw new Error('Parallax directive requires an <ion-content> element on the page to work.'); | ||
if (!ionContent) { | ||
console.error('A <ion-content> element is needed'); | ||
return false; | ||
} | ||
// Create image overlay | ||
this.innerScroll = ionContent.shadowRoot.querySelector('.inner-scroll'); | ||
this.originalToolbarHeight = this.ionToolbar.el.offsetHeight; | ||
this.toolbarContainer = | ||
this.ionToolbar.el.shadowRoot.querySelector('.toolbar-container'); | ||
this.toolbarBackground = this.ionToolbar.el.shadowRoot.querySelector('.toolbar-background'); | ||
this.color = this.color || window.getComputedStyle(this.toolbarBackground).backgroundColor; | ||
this.renderer.setStyle(this.header, 'pointer-events', 'none'); | ||
this.renderer.setStyle(this.toolbarContainer, 'pointer-events', 'all'); | ||
this.renderer.setStyle(this.toolbarContainer, 'align-items', 'baseline'); | ||
return true; | ||
} | ||
setupContentPadding() { | ||
const parentElement = this.header.parentElement; | ||
const ionContent = parentElement.querySelector('ion-content'); | ||
const mainContent = ionContent.shadowRoot.querySelector('main'); | ||
const { paddingTop } = window.getComputedStyle(mainContent); | ||
const calc = `calc(${paddingTop} + ${this.getMaxHeightWithUnits()})`; | ||
this.renderer.setStyle(this.header, 'position', 'absolute'); | ||
this.renderer.setStyle(this.innerScroll, 'padding-top', calc); | ||
} | ||
setupImageOverlay() { | ||
this.imageOverlay = this.renderer.createElement('div'); | ||
this.renderer.addClass(this.imageOverlay, 'image-overlay'); | ||
this.colorOverlay = this.renderer.createElement('div'); | ||
this.renderer.addClass(this.colorOverlay, 'color-overlay'); | ||
this.colorOverlay.appendChild(this.imageOverlay); | ||
this.header.appendChild(this.colorOverlay); | ||
// Copy title and buttons | ||
this.overlayTitle = this.ionTitle && this.ionTitle.cloneNode(true); | ||
if (this.overlayTitle) { | ||
this.renderer.addClass(this.overlayTitle, 'parallax-title'); | ||
setTimeout(() => { | ||
const toolbarTitle = this.overlayTitle.shadowRoot.querySelector('.toolbar-title'); | ||
this.renderer.setStyle(toolbarTitle, 'pointer-events', 'unset'); | ||
}); | ||
} | ||
if (this.overlayTitle) { | ||
this.imageOverlay.appendChild(this.overlayTitle); | ||
} | ||
if (this.barButtons) { | ||
this.imageOverlay.appendChild(this.barButtons); | ||
} | ||
} | ||
initStyles() { | ||
this.headerHeight = this.scrollContent.clientHeight; | ||
this.ticking = false; | ||
if (!this.scrollContent || !toolbar) { | ||
return; | ||
} | ||
// fetch styles | ||
this.maximumHeight = parseFloat(this.maximumHeight.toString()); | ||
this.headerMinHeight = this.toolbar.offsetHeight; | ||
this.scrollContentPaddingTop = window.getComputedStyle(this.scrollContent, null).paddingTop.replace('px', ''); | ||
this.scrollContentPaddingTop = parseFloat(this.scrollContentPaddingTop); | ||
this.originalToolbarBgColor = window.getComputedStyle(this.toolbarBackground, null).backgroundColor; | ||
if (!this.originalToolbarBgColor) { | ||
throw new Error('Error: toolbarBackround is null.'); | ||
} | ||
// header and title | ||
this.renderer.setStyle(this.header, 'position', 'relative'); | ||
if (this.overlayTitle) { | ||
this.renderer.setStyle(this.overlayTitle, 'color', this.titleColor); | ||
this.renderer.setStyle(this.overlayTitle, 'position', 'absolute'); | ||
this.renderer.setStyle(this.overlayTitle, 'width', '100%'); | ||
this.renderer.setStyle(this.overlayTitle, 'height', '100%'); | ||
this.renderer.setStyle(this.overlayTitle, 'text-align', 'center'); | ||
} | ||
// color overlay | ||
this.renderer.setStyle(this.colorOverlay, 'background-color', this.originalToolbarBgColor); | ||
this.renderer.setStyle(this.colorOverlay, 'height', `${this.maximumHeight}px`); | ||
this.renderer.setStyle(this.colorOverlay, 'position', 'absolute'); | ||
this.renderer.setStyle(this.colorOverlay, 'top', `${-this.headerMinHeight * 0}px`); | ||
this.renderer.setStyle(this.colorOverlay, 'left', '0'); | ||
this.renderer.setStyle(this.colorOverlay, 'width', '100%'); | ||
this.renderer.setStyle(this.colorOverlay, 'z-index', '10'); | ||
this.renderer.setStyle(this.colorOverlay, 'pointer-events', 'none'); | ||
// image overlay | ||
this.renderer.setStyle(this.imageOverlay, 'background-color', this.expandedColor); | ||
this.renderer.setStyle(this.imageOverlay, 'background-color', this.color); | ||
this.renderer.setStyle(this.imageOverlay, 'background-image', `url(${this.imageUrl || ''})`); | ||
this.renderer.setStyle(this.imageOverlay, 'height', `100%`); | ||
this.renderer.setStyle(this.imageOverlay, 'width', '100%'); | ||
this.renderer.setStyle(this.imageOverlay, 'pointer-events', 'none'); | ||
this.renderer.setStyle(this.imageOverlay, 'background-size', 'cover'); | ||
this.renderer.setStyle(this.imageOverlay, 'background-position', 'center'); | ||
// .toolbar-background | ||
this.renderer.setStyle(this.toolbarBackground, 'background-color', this.originalToolbarBgColor); | ||
// .bar-buttons | ||
if (this.barButtons) { | ||
this.renderer.setStyle(this.barButtons, 'pointer-events', 'all'); | ||
Array.from(this.barButtons.children).forEach(btn => { | ||
this.renderer.setStyle(btn, 'color', this.titleColor); | ||
}); | ||
} | ||
// .scroll-content | ||
if (this.scrollContent) { | ||
this.renderer.setAttribute(this.scrollContent, 'parallax', ''); | ||
this.renderer.setStyle(this.scrollContent, 'padding-top', `${this.maximumHeight + this.scrollContentPaddingTop - this.headerMinHeight}px`); | ||
} | ||
this.renderer.setStyle(this.imageOverlay, 'background-position', this.bgPosition); | ||
this.toolbarBackground.appendChild(this.imageOverlay); | ||
} | ||
initEvents() { | ||
window.addEventListener('resize', () => { | ||
this.headerHeight = this.scrollContent.clientHeight; | ||
}, false); | ||
if (this.scrollContent) { | ||
this.scrollContent.addEventListener('scroll', (e) => { | ||
if (!this.ticking) { | ||
window.requestAnimationFrame(() => { | ||
this.updateElasticHeader(); | ||
}); | ||
} | ||
this.ticking = true; | ||
}); | ||
} | ||
} | ||
updateElasticHeader() { | ||
if (!this.scrollContent || !toolbar) { | ||
return; | ||
} | ||
this.scrollTop = this.scrollContent.scrollTop; | ||
if (this.scrollTop >= 0) { | ||
this.translateAmt = this.scrollTop / 2; | ||
this.scaleAmt = 1; | ||
} | ||
else { | ||
this.translateAmt = 0; | ||
this.scaleAmt = -this.scrollTop / this.headerHeight + 1; | ||
} | ||
// Parallax total progress | ||
this.headerMinHeight = this.toolbar.offsetHeight; | ||
let progress = (this.maximumHeight - this.scrollTop - this.headerMinHeight) / (this.maximumHeight - this.headerMinHeight); | ||
progress = Math.max(progress, 0); | ||
// ion-header: set height | ||
let targetHeight = this.maximumHeight - this.scrollTop; | ||
targetHeight = Math.max(targetHeight, this.headerMinHeight); | ||
// .toolbar-background: change color | ||
this.renderer.setStyle(this.imageOverlay, 'height', `${targetHeight}px`); | ||
this.renderer.setStyle(this.imageOverlay, 'opacity', `${progress}`); | ||
this.renderer.setStyle(this.colorOverlay, 'height', `${targetHeight}px`); | ||
this.renderer.setStyle(this.colorOverlay, 'opacity', targetHeight > this.headerMinHeight ? '1' : '0'); | ||
this.renderer.setStyle(this.toolbarBackground, 'background-color', targetHeight > this.headerMinHeight ? 'transparent' : this.originalToolbarBgColor); | ||
// .bar-buttons | ||
if (this.barButtons) { | ||
if (targetHeight > this.headerMinHeight) { | ||
this.imageOverlay.append(this.barButtons); | ||
Array.from(this.barButtons.children).forEach(btn => { | ||
this.renderer.setStyle(btn, 'color', this.titleColor); | ||
setupEvents() { | ||
this.innerScroll.addEventListener('scroll', (_event) => { | ||
if (!this.ticking) { | ||
window.requestAnimationFrame(() => { | ||
this.updateProgress(); | ||
this.ticking = false; | ||
}); | ||
} | ||
else { | ||
this.toolbar.append(this.barButtons); | ||
Array.from(this.barButtons.children).forEach(btn => { | ||
this.renderer.setStyle(btn, 'color', 'unset'); | ||
}); | ||
} | ||
} | ||
this.ticking = false; | ||
this.ticking = true; | ||
}); | ||
} | ||
/** Update the parallax effect as per the current scroll of the ion-content */ | ||
updateProgress() { | ||
const progress = this.calcProgress(this.innerScroll, +this.height); | ||
this.progressLayerHeight(progress); | ||
this.progressLayerOpacity(progress); | ||
} | ||
progressLayerHeight(progress) { | ||
const h = Math.max(+this.height * (1 - progress), this.originalToolbarHeight); | ||
this.renderer.setStyle(this.toolbarContainer, 'height', `${h}px`); | ||
this.renderer.setStyle(this.imageOverlay, 'height', `${h}px`); | ||
} | ||
progressLayerOpacity(progress) { | ||
const op = 1 - progress; | ||
this.renderer.setStyle(this.imageOverlay, 'opacity', op); | ||
// this.renderer.setStyle(this.toolbarContainer, 'opacity', progress); | ||
} | ||
calcProgress(scrollingElement, maxHeight) { | ||
const scroll = +scrollingElement.scrollTop; | ||
const progress = Math.min(1, Math.max(0, scroll / maxHeight)); | ||
return progress; | ||
} | ||
} | ||
ParallaxDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.2", ngImport: i0, type: ParallaxDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); | ||
ParallaxDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.0.2", type: ParallaxDirective, selector: "ion-header[parallax]", inputs: { imageUrl: "imageUrl", expandedColor: "expandedColor", titleColor: "titleColor", maximumHeight: "maximumHeight" }, ngImport: i0 }); | ||
ParallaxDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.0.2", type: ParallaxDirective, selector: "ion-header[parallax]", inputs: { imageUrl: "imageUrl", color: "color", height: "height", bgPosition: "bgPosition" }, queries: [{ propertyName: "ionTitle", first: true, predicate: IonTitle, descendants: true }, { propertyName: "ionToolbar", first: true, predicate: IonToolbar, descendants: true }, { propertyName: "ionButtons", predicate: IonButtons }], ngImport: i0 }); | ||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.2", ngImport: i0, type: ParallaxDirective, decorators: [{ | ||
type: Directive, | ||
args: [{ | ||
selector: 'ion-header[parallax]' | ||
selector: 'ion-header[parallax]', | ||
}] | ||
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { imageUrl: [{ | ||
type: Input | ||
}], expandedColor: [{ | ||
}], color: [{ | ||
type: Input | ||
}], titleColor: [{ | ||
}], height: [{ | ||
type: Input | ||
}], maximumHeight: [{ | ||
}], bgPosition: [{ | ||
type: Input | ||
}], ionTitle: [{ | ||
type: ContentChild, | ||
args: [IonTitle, { static: false }] | ||
}], ionToolbar: [{ | ||
type: ContentChild, | ||
args: [IonToolbar, { static: false }] | ||
}], ionButtons: [{ | ||
type: ContentChildren, | ||
args: [IonButtons] | ||
}] } }); | ||
@@ -192,0 +142,0 @@ |
import * as i0 from "@angular/core"; | ||
import * as i1 from "./parallax.directive"; | ||
import * as i1 from "./ionic-header-parallax.directive"; | ||
export declare class IonicHeaderParallaxModule { | ||
@@ -4,0 +4,0 @@ static ɵfac: i0.ɵɵFactoryDeclaration<IonicHeaderParallaxModule, never>; |
{ | ||
"name": "ionic-header-parallax", | ||
"version": "3.0.0-dev", | ||
"version": "3.0.2", | ||
"description": "This directive enables parallax effect on `ion-header` elements to display a cover photo while on top of the page and transition it to the normal navbar when content is scrolled down.", | ||
"main": "bundles/ionic-header-parallax.umd.js", | ||
"peerDependencies": { | ||
@@ -29,2 +28,3 @@ "@angular/common": "^12.0.2", | ||
"homepage": "https://github.com/raschidJFR/ionic-header-parallax#readme", | ||
"main": "bundles/ionic-header-parallax.umd.js", | ||
"module": "fesm2015/ionic-header-parallax.js", | ||
@@ -31,0 +31,0 @@ "es2015": "fesm2015/ionic-header-parallax.js", |
@@ -0,2 +1,2 @@ | ||
export * from './lib/ionic-header-parallax.directive'; | ||
export * from './lib/ionic-header-parallax.module'; | ||
export * from './lib/parallax.directive'; |
@@ -1,13 +0,13 @@ | ||
# Parallax Header Directive for Ionic v4 # | ||
# Parallax Header Directive for Ionic | ||
This directive enables parallax effect on `ion-header` elements to display a cover photo while on top of the page and transition it to the normal navbar when content is scrolled down. | ||
> For Ionic 3 use version [1.1.0](https://www.npmjs.com/package/ionic-header-parallax/v/1.1.0) of this package: `$ npm i ionic-header-parallax@1.1.0`. | ||
> For Ionic versions `< 5`, check the [previous tags](https://www.npmjs.com/package/ionic-header-parallax?activeTab=versions) of this packate. | ||
* [Live Demo](https://raschidjfr.github.io/ionic-header-parallax) | ||
* [Code Playground](https://stackblitz.com/github/raschidjfr/ionic-header-parallax?file=src%2Fapp%2Fhome%2Fhome.page.html) | ||
- [Live Demo](https://raschidjfr.github.io/ionic-header-parallax) | ||
- [Code Playground](https://stackblitz.com/github/raschidjfr/ionic-header-parallax?file=src%2Fapp%2Fhome%2Fhome.page.html) | ||
![alt text](https://raw.githubusercontent.com/raschidJFR/ionic-header-parallax/master/gif.gif) | ||
## Set Up ## | ||
## Set Up | ||
@@ -26,3 +26,3 @@ 1. Install package: `$ npm i ionic-header-parallax`. | ||
## Usage ## | ||
## Usage | ||
@@ -32,30 +32,20 @@ Just add the attribute `parallax` to any `<ion-header>` element: | ||
```html | ||
<ion-header parallax></ion-header> | ||
``` | ||
Optional attributes: | ||
* `imageUrl (string)`: The background image to show while expanded. | ||
* `maximumHeight (number)`: The height for the header when expanded. Default is `200`. | ||
* `expandedColor (string)`: The color (web hex formatted) to show while the header is expanded when no `imageUrl` is set. When scrolled it will fade to the navbar/toolbar's color or the one configured in `<toolbar color="">` attribute. | ||
* `titleColor (string)`: The text color (web hex formatted) for `<ion-title>` and `<ion-back-button>` elements when expanded. They will turn to their default color on cover collapse. | ||
Example: | ||
```html | ||
<ion-header parallax imageUrl="https://picsum.photos/350" maximumHeight="350" expandedColor="#AAA" titleColor="white"> | ||
<ion-header parallax imageUrl="https://picsum.photos/350" height="350" bgPosition="top"> | ||
<ion-toolbar color="primary"> | ||
<ion-title> | ||
Parallax Header | ||
</ion-title> | ||
<ion-title> Parallax Header </ion-title> | ||
</ion-toolbar> | ||
</ion-header> | ||
<ion-content> | ||
Some content here | ||
</ion-content> | ||
<ion-content> Some content here </ion-content> | ||
``` | ||
## Modifying the Source Code / Contributing ## | ||
| Parameter | Description | | ||
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `imageUrl (string)` | The background image to show while expanded. | | ||
| `height (number \| string)` | The height for the header when expanded. If the value is a number, it will be set in `px`. If the value is a string it will be passed as is (eg: `"20rem"`) | | ||
| `color (string)` | The color (web hex formatted) to show while the header is expanded when no `imageUrl` is set. When scrolled it will fade to the toolbar's color. | | ||
| `bgPosition ('top' \| 'center' \| 'bottom')` | The position of the image in the header. This parameter slightly changes the feeling of the animation. | | ||
## Source Code / Contributing | ||
I don't plan to be maintaining this package full-time, but as I'm usually developing in Ionic I'll be glad to update it any time I make some upgrades for myself. | ||
@@ -66,9 +56,8 @@ Contributions are very welcome. Find the instructions in the [CONTRIBUTING.md](CONTRIBUTING.md) file. | ||
## Credits ## | ||
## Credits | ||
Raschid JF. Rafaelly | ||
<me@raschidjfr.dev> | ||
<hello@raschidjfr.dev> | ||
<https://raschidjfr.dev> | ||
This is an adaptation of this awesome tutorial on v2 by [Josh Morony](https://www.joshmorony.com/how-to-create-a-directive-in-ionic-2-parallax-header/). Thanks. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
73136
594
61