UNPKG

@taiga-ui/addon-mobile

Version:

Extension package for Taiga UI that adds support for mobile specific behaviors such as custom data pickers, dropdowns, etc.

154 lines (147 loc) 15.3 kB
import { NgForOf, NgIf } from '@angular/common'; import * as i0 from '@angular/core'; import { ElementRef, Component, ChangeDetectionStrategy, ViewChildren, InjectionToken, inject, Injectable, Directive } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { EMPTY_QUERY } from '@taiga-ui/cdk/constants'; import * as i1 from '@taiga-ui/cdk/directives/animated'; import { TuiAnimated } from '@taiga-ui/cdk/directives/animated'; import { tuiCloseWatcher, tuiZonefull } from '@taiga-ui/cdk/observables'; import { tuiInjectElement } from '@taiga-ui/cdk/utils/dom'; import { tuiProvide, tuiProvideOptions } from '@taiga-ui/cdk/utils/miscellaneous'; import { TUI_SCROLL_REF } from '@taiga-ui/core/tokens'; import { injectContext, PolymorpheusOutlet } from '@taiga-ui/polymorpheus'; import { Subject, merge, exhaustMap, isObservable, take, of, filter, startWith, pairwise } from 'rxjs'; import { TuiPopoverDirective } from '@taiga-ui/cdk/directives/popover'; import { TuiPopoverService, TuiThemeColorService, tuiAsPopover } from '@taiga-ui/cdk/services'; import { TUI_DIALOGS } from '@taiga-ui/core/components/dialog'; const REQUIRED_ERROR = new Error(ngDevMode ? 'Required dialog was dismissed' : ''); class TuiSheetDialogComponent { constructor() { this.stops = EMPTY_QUERY; this.el = tuiInjectElement(); this.pointers = 0; this.context = injectContext(); this.close$ = new Subject(); this.$ = merge(this.close$, tuiCloseWatcher()) .pipe(tuiZonefull(), exhaustMap(() => { if (isObservable(this.context.closeable)) { if (this.el.scrollTop <= 0) { this.el.scrollTo({ top: this.initial, behavior: 'smooth' }); } return this.context.closeable.pipe(take(1)); } return of(this.context.closeable); }), filter(Boolean), takeUntilDestroyed()) .subscribe(() => this.close()); } ngAfterViewInit() { this.el.scrollTop = this.initial; } onPointerChange(delta) { this.pointers = Math.max(this.pointers + delta, 0); if (!this.pointers && this.el.scrollTop <= 0) { this.close$.next(); } } get initial() { if (!this.context.closeable) { return 0; } return (this.stops .map((e) => e.nativeElement.offsetTop - this.context.offset) .concat(this.el.clientHeight ?? Infinity)[this.context.initial] ?? 0); } close() { if (this.context.required) { this.context.$implicit.error(REQUIRED_ERROR); } else { this.context.$implicit.complete(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TuiSheetDialogComponent, isStandalone: true, selector: "tui-sheet-dialog", host: { listeners: { "document:touchstart.passive.zoneless": "onPointerChange(1)", "document:touchend.zoneless": "onPointerChange(-1)", "document:touchcancel.zoneless": "onPointerChange(-1)", "scroll.zoneless": "onPointerChange(0)", "click.self": "close$.next()" }, properties: { "style.--tui-offset.px": "context.offset", "class._closeable": "context.closeable", "class._fullscreen": "context.fullscreen === true" } }, providers: [tuiProvide(TUI_SCROLL_REF, ElementRef)], viewQueries: [{ propertyName: "stops", predicate: ["stops"], descendants: true }], hostDirectives: [{ directive: i1.TuiAnimated }], ngImport: i0, template: "<div class=\"t-stops\">\n <div\n *ngFor=\"let stop of context.stops\"\n #stops\n class=\"t-stop\"\n [style.margin-top]=\"stop\"\n ></div>\n</div>\n<div class=\"t-sheet\">\n <div\n *ngIf=\"context.bar\"\n class=\"t-top\"\n ></div>\n <h2\n *ngIf=\"context.label\"\n class=\"t-heading\"\n [id]=\"context.id\"\n >\n <ng-container *polymorpheusOutlet=\"context.label as label; context: context\">\n {{ label }}\n </ng-container>\n </h2>\n <div class=\"t-content\">\n <ng-container *polymorpheusOutlet=\"context.content as text; context: context\">\n {{ text }}\n </ng-container>\n </div>\n</div>\n", styles: [":host{scrollbar-width:none;-ms-overflow-style:none;display:flex;inline-size:100%;max-inline-size:40rem;block-size:calc(100% - max(var(--tui-offset),env(safe-area-inset-top)));flex-direction:column;font:var(--tui-font-text-m);overflow-y:scroll;scroll-snap-type:y mandatory;margin:max(var(--tui-offset),env(safe-area-inset-top)) auto 0;border-radius:.75rem .75rem 0 0}:host::-webkit-scrollbar,:host::-webkit-scrollbar-thumb{display:none}:host.tui-enter,:host.tui-leave{animation-name:tuiFade,tuiSlide}:host:before{position:absolute;top:0;left:0;inline-size:100%;block-size:100%;content:\"\";z-index:-1}:host._closeable{display:block}:host._closeable .t-stops{display:flex}:host._fullscreen{display:block}:host._fullscreen .t-sheet{display:flex;flex-direction:column;min-block-size:100%}:host._fullscreen .t-content{display:flex;flex-direction:column;flex-grow:1}.t-stops{display:none;block-size:100%;scroll-snap-stop:always;scroll-snap-align:start;pointer-events:none}.t-stop{position:relative;top:env(safe-area-inset-bottom);scroll-snap-stop:normal;scroll-snap-align:start;block-size:1rem;inline-size:1rem}.t-sheet{scrollbar-width:none;-ms-overflow-style:none;inline-size:100%;box-shadow:var(--tui-shadow-small);border-radius:inherit;padding:0 1rem;margin-block-start:auto;background:var(--tui-background-elevation-1);box-sizing:border-box;scroll-snap-stop:always;scroll-snap-align:start}.t-sheet::-webkit-scrollbar,.t-sheet::-webkit-scrollbar-thumb{display:none}.t-top{position:sticky;top:0;z-index:1;block-size:1.5rem;margin:0 -1rem;border-radius:inherit;background:var(--tui-background-elevation-1)}.t-top:after{content:\"\";position:absolute;top:.5rem;left:50%;inline-size:2rem;block-size:.25rem;transform:translate(-50%);background:var(--tui-border-normal);border-radius:1rem}.t-heading{position:sticky;top:1.5rem;z-index:1;margin:0 -1rem;padding:.75rem 1rem;font:var(--tui-font-heading-6);background:var(--tui-background-elevation-1)}.t-heading:first-child{top:0;border-radius:inherit}.t-heading:last-child{padding-block-end:1.5rem}.t-content{position:relative;isolation:isolate;padding-block-end:max(1.5rem,env(safe-area-inset-bottom));border-radius:inherit}.t-content:after{content:\"\";position:relative;top:max(1.5rem,env(safe-area-inset-bottom));z-index:-1;display:block;scroll-snap-stop:always;scroll-snap-align:end;border-image:conic-gradient(var(--tui-background-elevation-1) 0 0) fill 0/0/0 100vh 100vh}\n"], dependencies: [{ kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialogComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'tui-sheet-dialog', imports: [NgForOf, NgIf, PolymorpheusOutlet], changeDetection: ChangeDetectionStrategy.OnPush, providers: [tuiProvide(TUI_SCROLL_REF, ElementRef)], hostDirectives: [TuiAnimated], host: { '[style.--tui-offset.px]': 'context.offset', '[class._closeable]': 'context.closeable', '[class._fullscreen]': 'context.fullscreen === true', '(document:touchstart.passive.zoneless)': 'onPointerChange(1)', '(document:touchend.zoneless)': 'onPointerChange(-1)', '(document:touchcancel.zoneless)': 'onPointerChange(-1)', '(scroll.zoneless)': 'onPointerChange(0)', '(click.self)': 'close$.next()', }, template: "<div class=\"t-stops\">\n <div\n *ngFor=\"let stop of context.stops\"\n #stops\n class=\"t-stop\"\n [style.margin-top]=\"stop\"\n ></div>\n</div>\n<div class=\"t-sheet\">\n <div\n *ngIf=\"context.bar\"\n class=\"t-top\"\n ></div>\n <h2\n *ngIf=\"context.label\"\n class=\"t-heading\"\n [id]=\"context.id\"\n >\n <ng-container *polymorpheusOutlet=\"context.label as label; context: context\">\n {{ label }}\n </ng-container>\n </h2>\n <div class=\"t-content\">\n <ng-container *polymorpheusOutlet=\"context.content as text; context: context\">\n {{ text }}\n </ng-container>\n </div>\n</div>\n", styles: [":host{scrollbar-width:none;-ms-overflow-style:none;display:flex;inline-size:100%;max-inline-size:40rem;block-size:calc(100% - max(var(--tui-offset),env(safe-area-inset-top)));flex-direction:column;font:var(--tui-font-text-m);overflow-y:scroll;scroll-snap-type:y mandatory;margin:max(var(--tui-offset),env(safe-area-inset-top)) auto 0;border-radius:.75rem .75rem 0 0}:host::-webkit-scrollbar,:host::-webkit-scrollbar-thumb{display:none}:host.tui-enter,:host.tui-leave{animation-name:tuiFade,tuiSlide}:host:before{position:absolute;top:0;left:0;inline-size:100%;block-size:100%;content:\"\";z-index:-1}:host._closeable{display:block}:host._closeable .t-stops{display:flex}:host._fullscreen{display:block}:host._fullscreen .t-sheet{display:flex;flex-direction:column;min-block-size:100%}:host._fullscreen .t-content{display:flex;flex-direction:column;flex-grow:1}.t-stops{display:none;block-size:100%;scroll-snap-stop:always;scroll-snap-align:start;pointer-events:none}.t-stop{position:relative;top:env(safe-area-inset-bottom);scroll-snap-stop:normal;scroll-snap-align:start;block-size:1rem;inline-size:1rem}.t-sheet{scrollbar-width:none;-ms-overflow-style:none;inline-size:100%;box-shadow:var(--tui-shadow-small);border-radius:inherit;padding:0 1rem;margin-block-start:auto;background:var(--tui-background-elevation-1);box-sizing:border-box;scroll-snap-stop:always;scroll-snap-align:start}.t-sheet::-webkit-scrollbar,.t-sheet::-webkit-scrollbar-thumb{display:none}.t-top{position:sticky;top:0;z-index:1;block-size:1.5rem;margin:0 -1rem;border-radius:inherit;background:var(--tui-background-elevation-1)}.t-top:after{content:\"\";position:absolute;top:.5rem;left:50%;inline-size:2rem;block-size:.25rem;transform:translate(-50%);background:var(--tui-border-normal);border-radius:1rem}.t-heading{position:sticky;top:1.5rem;z-index:1;margin:0 -1rem;padding:.75rem 1rem;font:var(--tui-font-heading-6);background:var(--tui-background-elevation-1)}.t-heading:first-child{top:0;border-radius:inherit}.t-heading:last-child{padding-block-end:1.5rem}.t-content{position:relative;isolation:isolate;padding-block-end:max(1.5rem,env(safe-area-inset-bottom));border-radius:inherit}.t-content:after{content:\"\";position:relative;top:max(1.5rem,env(safe-area-inset-bottom));z-index:-1;display:block;scroll-snap-stop:always;scroll-snap-align:end;border-image:conic-gradient(var(--tui-background-elevation-1) 0 0) fill 0/0/0 100vh 100vh}\n"] }] }], propDecorators: { stops: [{ type: ViewChildren, args: ['stops'] }] } }); const TUI_SHEET_DIALOG_DEFAULT_OPTIONS = { label: '', stops: [], initial: 0, offset: 16, closeable: true, data: undefined, bar: true, fullscreen: false, required: false, }; /** * Default parameters for mobile dialog component */ const TUI_SHEET_DIALOG_OPTIONS = new InjectionToken(ngDevMode ? 'TUI_SHEET_DIALOG_OPTIONS' : '', { factory: () => TUI_SHEET_DIALOG_DEFAULT_OPTIONS, }); function tuiSheetDialogOptionsProvider(options) { return tuiProvideOptions(TUI_SHEET_DIALOG_OPTIONS, options, TUI_SHEET_DIALOG_DEFAULT_OPTIONS); } const THEME = '#404040'; class TuiSheetDialogService extends TuiPopoverService { constructor() { super(...arguments); this.theme = inject(TuiThemeColorService); this.initial = this.theme.color; this.$ = this.items$ .pipe(startWith([]), pairwise(), takeUntilDestroyed()) .subscribe(([prev, next]) => { if (!prev.length && next.length) { this.initial = this.theme.color; this.theme.color = THEME; } if (!next.length && prev.length) { this.theme.color = this.initial; } }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialogService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialogService, providedIn: 'root', useFactory: () => new TuiSheetDialogService(TUI_DIALOGS, TuiSheetDialogComponent, inject(TUI_SHEET_DIALOG_OPTIONS)) }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialogService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', useFactory: () => new TuiSheetDialogService(TUI_DIALOGS, TuiSheetDialogComponent, inject(TUI_SHEET_DIALOG_OPTIONS)), }] }] }); class TuiSheetDialog extends TuiPopoverDirective { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialog, deps: null, target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: TuiSheetDialog, isStandalone: true, selector: "ng-template[tuiSheetDialog]", inputs: { options: ["tuiSheetDialogOptions", "options"], open: ["tuiSheetDialog", "open"] }, outputs: { openChange: "tuiSheetDialogChange" }, providers: [tuiAsPopover(TuiSheetDialogService)], usesInheritance: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSheetDialog, decorators: [{ type: Directive, args: [{ standalone: true, selector: 'ng-template[tuiSheetDialog]', inputs: ['options: tuiSheetDialogOptions', 'open: tuiSheetDialog'], outputs: ['openChange: tuiSheetDialogChange'], providers: [tuiAsPopover(TuiSheetDialogService)], }] }] }); /** * Generated bundle index. Do not edit. */ export { TUI_SHEET_DIALOG_DEFAULT_OPTIONS, TUI_SHEET_DIALOG_OPTIONS, TuiSheetDialog, TuiSheetDialogComponent, TuiSheetDialogService, tuiSheetDialogOptionsProvider }; //# sourceMappingURL=taiga-ui-addon-mobile-components-sheet-dialog.mjs.map