ngx-ui-tour-ionic
Version:
UI tour library for Angular 15+
211 lines (201 loc) • 20.5 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, inject, input, Component, ChangeDetectionStrategy, signal, TemplateRef, ViewChild, Input, ContentChild, ElementRef, Directive, NgModule } from '@angular/core';
import { TourService, TourHotkeyListenerComponent, BaseTourProxyAnchor } from 'ngx-ui-tour-core';
import { Config, IonButton, IonCard, IonCardContent, IonCardHeader, IonCardTitle, IonIcon, createAnimation, IonPopover } from '@ionic/angular/standalone';
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
import { addIcons } from 'ionicons';
import { closeOutline, chevronBackOutline, chevronForwardOutline } from 'ionicons/icons';
import { firstValueFrom } from 'rxjs';
class TourStepTemplateService {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourStepTemplateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourStepTemplateService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourStepTemplateService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
class IonTourService extends TourService {
constructor() {
super(...arguments);
this.config = inject(Config);
this.document = inject(DOCUMENT);
}
initialize(steps, stepDefaults) {
const userDefaults = this.getDefaults(), isIOS = this.config.get('mode') === 'ios';
stepDefaults ??= {};
stepDefaults.backdropConfig ??= userDefaults?.backdropConfig ?? {};
stepDefaults.backdropConfig.parentContainer ??= userDefaults?.backdropConfig?.parentContainer ?? 'ion-app';
stepDefaults.delayAfterNavigation ??= userDefaults?.delayAfterNavigation ?? (isIOS ? 700 : 500);
stepDefaults.trapFocus ??= userDefaults?.trapFocus ?? false;
super.initialize(steps, stepDefaults);
}
// noinspection JSUnusedGlobalSymbols
showStep(step) {
// In case "scrollContainer" is already set to HTMLElement, we DO want to set it again since the current
// html element reference might be already removed from DOM
if (step.smoothScroll && (!step.scrollContainer || typeof step.scrollContainer !== 'string')) {
const docEl = this.document.documentElement, tabsRouter = docEl.querySelector('ion-router-outlet[tabs=true]'), generalRouter = docEl.querySelector('ion-router-outlet'), router = tabsRouter ?? generalRouter, ionContent = router ? router.querySelector(':scope > .ion-page:not(.ion-page-hidden) ion-content') :
docEl.querySelector('ion-content');
step.scrollContainer = ionContent?.shadowRoot.querySelector('[part=scroll]');
}
return super.showStep(step);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: IonTourService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: IonTourService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: IonTourService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
class TourDefaultStepTemplateComponent {
constructor() {
this.step = input.required();
this.tourService = inject(IonTourService);
this.addIonicIcons();
}
addIonicIcons() {
addIcons({
closeOutline,
chevronBackOutline,
chevronForwardOutline
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourDefaultStepTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: TourDefaultStepTemplateComponent, isStandalone: true, selector: "tour-default-step-template", inputs: { step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let step = this.step();\r\n\r\n<ion-card>\r\n <ion-card-header>\r\n <ion-card-title>{{step.title}}</ion-card-title>\r\n <ion-button\r\n class=\"close\"\r\n fill=\"clear\"\r\n shape=\"round\"\r\n (click)=\"tourService.end()\"\r\n >\r\n <ion-icon slot=\"icon-only\" name=\"close-outline\"></ion-icon>\r\n </ion-button>\r\n </ion-card-header>\r\n\r\n <ion-card-content\r\n [innerHTML]=\"step.content\"\r\n ></ion-card-content>\r\n\r\n <div\r\n class=\"footer\"\r\n [class.no-progress]=\"!step.showProgress\"\r\n >\r\n <ion-button\r\n fill=\"clear\"\r\n [disabled]=\"!tourService.hasPrev(step)\"\r\n (click)=\"tourService.prev()\"\r\n >\r\n <ion-icon slot=\"start\" name=\"chevron-back-outline\"></ion-icon>\r\n {{ step.prevBtnTitle }}\r\n </ion-button>\r\n @if (step.showProgress) {\r\n <div class=\"progress\">{{ tourService.steps.indexOf(step) + 1 }} / {{ tourService.steps.length }}</div>\r\n }\r\n @if (tourService.hasNext(step) && !step.nextOnAnchorClick) {\r\n <ion-button\r\n fill=\"clear\"\r\n (click)=\"tourService.next()\"\r\n >\r\n {{ step.nextBtnTitle }}\r\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\r\n </ion-button>\r\n }\r\n @if (!tourService.hasNext(step)) {\r\n <ion-button\r\n fill=\"clear\"\r\n (click)=\"tourService.end()\"\r\n >\r\n {{ step.endBtnTitle }}\r\n </ion-button>\r\n }\r\n </div>\r\n</ion-card>\r\n", styles: ["ion-card{margin:0;pointer-events:auto}ion-card-header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:8px 16px}ion-card-header ion-card-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}ion-button.close{--padding-start: 5px;--padding-end: 5px;--padding-top: 5px;--padding-bottom: 5px;margin:0 -8px 0 0}.footer{display:grid;grid-template-columns:1fr auto 1fr;padding:0 8px 8px;align-items:center;gap:8px}.footer>*{max-width:fit-content}.footer>*:last-child{justify-self:flex-end}.footer .progress{font-size:12px;font-weight:600;color:#00000061;white-space:nowrap}.footer.no-progress{grid-template-columns:1fr 1fr}.footer ion-button{text-transform:capitalize}\n"], dependencies: [{ kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourDefaultStepTemplateComponent, decorators: [{
type: Component,
args: [{ selector: 'tour-default-step-template', imports: [
IonButton,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonIcon
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let step = this.step();\r\n\r\n<ion-card>\r\n <ion-card-header>\r\n <ion-card-title>{{step.title}}</ion-card-title>\r\n <ion-button\r\n class=\"close\"\r\n fill=\"clear\"\r\n shape=\"round\"\r\n (click)=\"tourService.end()\"\r\n >\r\n <ion-icon slot=\"icon-only\" name=\"close-outline\"></ion-icon>\r\n </ion-button>\r\n </ion-card-header>\r\n\r\n <ion-card-content\r\n [innerHTML]=\"step.content\"\r\n ></ion-card-content>\r\n\r\n <div\r\n class=\"footer\"\r\n [class.no-progress]=\"!step.showProgress\"\r\n >\r\n <ion-button\r\n fill=\"clear\"\r\n [disabled]=\"!tourService.hasPrev(step)\"\r\n (click)=\"tourService.prev()\"\r\n >\r\n <ion-icon slot=\"start\" name=\"chevron-back-outline\"></ion-icon>\r\n {{ step.prevBtnTitle }}\r\n </ion-button>\r\n @if (step.showProgress) {\r\n <div class=\"progress\">{{ tourService.steps.indexOf(step) + 1 }} / {{ tourService.steps.length }}</div>\r\n }\r\n @if (tourService.hasNext(step) && !step.nextOnAnchorClick) {\r\n <ion-button\r\n fill=\"clear\"\r\n (click)=\"tourService.next()\"\r\n >\r\n {{ step.nextBtnTitle }}\r\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\r\n </ion-button>\r\n }\r\n @if (!tourService.hasNext(step)) {\r\n <ion-button\r\n fill=\"clear\"\r\n (click)=\"tourService.end()\"\r\n >\r\n {{ step.endBtnTitle }}\r\n </ion-button>\r\n }\r\n </div>\r\n</ion-card>\r\n", styles: ["ion-card{margin:0;pointer-events:auto}ion-card-header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:8px 16px}ion-card-header ion-card-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}ion-button.close{--padding-start: 5px;--padding-end: 5px;--padding-top: 5px;--padding-bottom: 5px;margin:0 -8px 0 0}.footer{display:grid;grid-template-columns:1fr auto 1fr;padding:0 8px 8px;align-items:center;gap:8px}.footer>*{max-width:fit-content}.footer>*:last-child{justify-self:flex-end}.footer .progress{font-size:12px;font-weight:600;color:#00000061;white-space:nowrap}.footer.no-progress{grid-template-columns:1fr 1fr}.footer ion-button{text-transform:capitalize}\n"] }]
}], ctorParameters: () => [] });
class TourStepTemplateComponent extends TourHotkeyListenerComponent {
constructor() {
super(...arguments);
this.step = signal({});
this.noopLeaveAnimation = () => createAnimation();
this.tourService = inject(IonTourService);
this.tourStepTemplateService = inject(TourStepTemplateService);
}
ngAfterViewInit() {
this.tourStepTemplateService.templateComponent = this;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourStepTemplateComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: TourStepTemplateComponent, isStandalone: true, selector: "tour-step-template", inputs: { stepTemplate: "stepTemplate" }, queries: [{ propertyName: "stepTemplateContent", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "ionPopover", first: true, predicate: IonPopover, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "@let step = this.step();\r\n\r\n<ion-popover\r\n [leaveAnimation]=\"noopLeaveAnimation\"\r\n [backdropDismiss]=\"false\"\r\n [keyboardClose]=\"false\"\r\n [showBackdrop]=\"false\"\r\n [dismissOnSelect]=\"false\"\r\n [style.--min-width]=\"step?.stepDimensions?.minWidth\"\r\n [style.--max-width]=\"step?.stepDimensions?.maxWidth\"\r\n [style.--width]=\"step?.stepDimensions?.width\"\r\n [arrow]=\"step?.showArrow ?? true\"\r\n [focusTrap]=\"step?.trapFocus ?? false\"\r\n>\r\n <ng-template>\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n stepTemplate || stepTemplateContent || defaultTemplate;\r\n context: {step: step}\r\n \"\r\n ></ng-container>\r\n </ng-template>\r\n</ion-popover>\r\n\r\n<ng-template #defaultTemplate let-step=\"step\">\r\n <tour-default-step-template\r\n [step]=\"step\"\r\n />\r\n</ng-template>\r\n", styles: ["ion-popover{pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IonPopover, selector: "ion-popover" }, { kind: "component", type: TourDefaultStepTemplateComponent, selector: "tour-default-step-template", inputs: ["step"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourStepTemplateComponent, decorators: [{
type: Component,
args: [{ selector: 'tour-step-template', imports: [
NgTemplateOutlet,
IonPopover,
TourDefaultStepTemplateComponent
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let step = this.step();\r\n\r\n<ion-popover\r\n [leaveAnimation]=\"noopLeaveAnimation\"\r\n [backdropDismiss]=\"false\"\r\n [keyboardClose]=\"false\"\r\n [showBackdrop]=\"false\"\r\n [dismissOnSelect]=\"false\"\r\n [style.--min-width]=\"step?.stepDimensions?.minWidth\"\r\n [style.--max-width]=\"step?.stepDimensions?.maxWidth\"\r\n [style.--width]=\"step?.stepDimensions?.width\"\r\n [arrow]=\"step?.showArrow ?? true\"\r\n [focusTrap]=\"step?.trapFocus ?? false\"\r\n>\r\n <ng-template>\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n stepTemplate || stepTemplateContent || defaultTemplate;\r\n context: {step: step}\r\n \"\r\n ></ng-container>\r\n </ng-template>\r\n</ion-popover>\r\n\r\n<ng-template #defaultTemplate let-step=\"step\">\r\n <tour-default-step-template\r\n [step]=\"step\"\r\n />\r\n</ng-template>\r\n", styles: ["ion-popover{pointer-events:none}\n"] }]
}], propDecorators: { ionPopover: [{
type: ViewChild,
args: [IonPopover, { static: true }]
}], stepTemplate: [{
type: Input
}], stepTemplateContent: [{
type: ContentChild,
args: [TemplateRef]
}] } });
class TourAnchorIonPopoverDirective {
constructor() {
this.isActive = signal(false);
this.element = inject(ElementRef);
this.tourService = inject(IonTourService);
this.stepTemplateService = inject(TourStepTemplateService);
}
ngOnInit() {
this.tourService.register(this.tourAnchor, this);
}
ngOnDestroy() {
this.tourService.unregister(this.tourAnchor);
}
async showTourStep(step) {
const templateComponent = this.stepTemplateService.templateComponent, popover = templateComponent.ionPopover;
if (popover.isCmpOpen) {
await firstValueFrom(popover.didDismiss);
}
this.isActive.set(true);
templateComponent.step.set(step);
popover.alignment = step.placement?.alignment;
popover.side = step.placement?.side ?? 'bottom';
popover.cssClass = step.popoverClass;
const event = {
target: this.element.nativeElement
};
await popover.present(event);
}
hideTourStep() {
this.isActive.set(false);
const popover = this.stepTemplateService.templateComponent.ionPopover;
popover.dismiss();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourAnchorIonPopoverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: TourAnchorIonPopoverDirective, isStandalone: true, selector: "[tourAnchor]", inputs: { tourAnchor: "tourAnchor" }, host: { properties: { "class.touranchor--is-active": "isActive()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourAnchorIonPopoverDirective, decorators: [{
type: Directive,
args: [{
selector: '[tourAnchor]',
host: {
'[class.touranchor--is-active]': 'isActive()'
}
}]
}], propDecorators: { tourAnchor: [{
type: Input
}] } });
class TourProxyAnchorComponent extends BaseTourProxyAnchor {
constructor() {
super(...arguments);
// noinspection JSUnusedGlobalSymbols
this.anchorDirective = inject(TourAnchorIonPopoverDirective, {
host: true
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourProxyAnchorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: TourProxyAnchorComponent, isStandalone: true, selector: "tour-proxy-anchor", inputs: { anchorEl: "anchorEl" }, usesInheritance: true, hostDirectives: [{ directive: TourAnchorIonPopoverDirective, inputs: ["tourAnchor", "anchorId"] }], ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourProxyAnchorComponent, decorators: [{
type: Component,
args: [{
selector: 'tour-proxy-anchor',
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{
directive: TourAnchorIonPopoverDirective,
inputs: ['tourAnchor: anchorId']
}]
}]
}], propDecorators: { anchorEl: [{
type: Input,
args: [{ required: true }]
}] } });
const COMPONENTS = [TourStepTemplateComponent, TourAnchorIonPopoverDirective, TourProxyAnchorComponent];
class TourIonPopoverModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourIonPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: TourIonPopoverModule, imports: [TourStepTemplateComponent, TourAnchorIonPopoverDirective, TourProxyAnchorComponent], exports: [TourStepTemplateComponent, TourAnchorIonPopoverDirective, TourProxyAnchorComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourIonPopoverModule, imports: [TourStepTemplateComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: TourIonPopoverModule, decorators: [{
type: NgModule,
args: [{
imports: COMPONENTS,
exports: COMPONENTS
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { TourAnchorIonPopoverDirective, TourIonPopoverModule, TourProxyAnchorComponent, IonTourService as TourService, TourStepTemplateComponent };
//# sourceMappingURL=ngx-ui-tour-ionic.mjs.map