UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

272 lines (263 loc) 15.6 kB
import * as i0 from '@angular/core'; import { InjectionToken, inject, input, model, signal, ChangeDetectionStrategy, ViewEncapsulation, Component, PLATFORM_ID, Injectable, viewChild, ElementRef, Directive } from '@angular/core'; import { TUI_VERSION } from '@taiga-ui/cdk/constants'; import { tuiInjectElement, tuiGetActualTarget, tuiIsElement } from '@taiga-ui/cdk/utils/dom'; import { isPlatformBrowser, DOCUMENT } from '@angular/common'; import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; import { WaMutationObserverService, WA_MUTATION_OBSERVER_INIT } from '@ng-web-apis/mutation-observer'; import { WaResizeObserverService } from '@ng-web-apis/resize-observer'; import { tuiZonefreeScheduler, tuiTypedFromEvent } from '@taiga-ui/cdk/observables'; import { tuiArrayShallowEquals, tuiPx } from '@taiga-ui/cdk/utils/miscellaneous'; import { Subject, debounce, timer, filter, map, Subscription, BehaviorSubject, combineLatest, distinctUntilChanged, startWith, debounceTime, merge } from 'rxjs'; const tuiTilesSwap = (order, currentIndex, newIndex) => { if (!order.has(currentIndex) || !order.has(newIndex)) { return order; } const dragged = order.get(currentIndex) ?? currentIndex; const placement = order.get(newIndex) ?? newIndex; const newOrder = new Map(order); newOrder.set(currentIndex, placement); newOrder.set(newIndex, dragged); return newOrder; }; const tuiTilesShift = (order, currentIndex, newIndex) => { if (!order.has(currentIndex) || !order.has(newIndex)) { return order; } const dragged = order.get(currentIndex) ?? currentIndex; const placement = order.get(newIndex) ?? newIndex; const newOrder = new Map(order); const flipped = new Map(Array.from(order).map(([a, b]) => [b, a])); if ((placement - dragged) / Math.abs(placement - dragged) > 0) { for (let i = placement; i > dragged; i--) { newOrder.set(flipped.get(i) ?? i, i - 1); } } else { for (let i = placement; i < dragged; i++) { newOrder.set(flipped.get(i) ?? i, i + 1); } } newOrder.set(currentIndex, placement); return newOrder; }; const TUI_TILES_REORDER = new InjectionToken(ngDevMode ? 'TUI_TILES_REORDER' : '', { factory: () => tuiTilesSwap }); class TuiTilesComponent { constructor() { this.el$ = new Subject(); this.handler = inject(TUI_TILES_REORDER); this.sub = this.el$ .pipe(debounce(() => timer(this.debounce())), filter(this.filter.bind(this)), map((element) => this.reorder(element)), takeUntilDestroyed()) .subscribe((order) => this.order.set(order)); this.debounce = input(0); this.order = model(new Map()); this.element = signal(null); this.el = tuiInjectElement(); } rearrange(element) { this.el$.next(element); } filter(element) { return !!this.element() && !!element && this.element() !== element; } reorder(element) { const elements = Array.from(this.el.children); const currentIndex = elements.indexOf(this.element() || element); const newIndex = elements.indexOf(element); const order = this.order().size ? new Map(this.order()) : new Map(elements.map((_, index) => [index, index])); return this.handler(order, currentIndex, newIndex); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTilesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.21", type: TuiTilesComponent, isStandalone: true, selector: "tui-tiles", inputs: { debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null }, order: { classPropertyName: "order", publicName: "order", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { order: "orderChange" }, host: { attributes: { "data-tui-version": "5.7.0" }, listeners: { "pointerleave.zoneless": "rearrange()" } }, providers: [ WaResizeObserverService, WaMutationObserverService, { provide: WA_MUTATION_OBSERVER_INIT, useValue: { childList: true }, }, ], ngImport: i0, template: '<ng-content />', isInline: true, styles: ["tui-tiles:where(*[data-tui-version=\"5.7.0\"]){position:relative;z-index:0;display:grid;grid-auto-flow:dense;justify-items:stretch}tui-tiles:where(*[data-tui-version=\"5.7.0\"])._dragged tui-tile>.t-wrapper{pointer-events:none}tui-tiles:where(*[data-tui-version=\"5.7.0\"])._dragged tui-tile:not(._dragged)>.t-wrapper,tui-tiles:where(*[data-tui-version=\"5.7.0\"]):not(._dragged) tui-tile._dragged>.t-wrapper{transition-property:all;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;transition-delay:1ms}tui-tile:where(*[data-tui-version=\"5.7.0\"])>.t-wrapper{position:absolute;z-index:0;border-radius:inherit}tui-tile:where(*[data-tui-version=\"5.7.0\"])._dragged>.t-wrapper,tui-tile:where(*[data-tui-version=\"5.7.0\"]):has(tui-tile:where(*[data-tui-version=\"5.7.0\"])._dragged)>.t-wrapper{z-index:1}tui-tile:where(*[data-tui-version=\"5.7.0\"]) [tuiTileHandle]{touch-action:none;-webkit-user-select:none;user-select:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTilesComponent, decorators: [{ type: Component, args: [{ selector: 'tui-tiles', template: '<ng-content />', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [ WaResizeObserverService, WaMutationObserverService, { provide: WA_MUTATION_OBSERVER_INIT, useValue: { childList: true }, }, ], host: { 'data-tui-version': TUI_VERSION, '(pointerleave.zoneless)': 'rearrange()' }, styles: ["tui-tiles:where(*[data-tui-version=\"5.7.0\"]){position:relative;z-index:0;display:grid;grid-auto-flow:dense;justify-items:stretch}tui-tiles:where(*[data-tui-version=\"5.7.0\"])._dragged tui-tile>.t-wrapper{pointer-events:none}tui-tiles:where(*[data-tui-version=\"5.7.0\"])._dragged tui-tile:not(._dragged)>.t-wrapper,tui-tiles:where(*[data-tui-version=\"5.7.0\"]):not(._dragged) tui-tile._dragged>.t-wrapper{transition-property:all;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;transition-delay:1ms}tui-tile:where(*[data-tui-version=\"5.7.0\"])>.t-wrapper{position:absolute;z-index:0;border-radius:inherit}tui-tile:where(*[data-tui-version=\"5.7.0\"])._dragged>.t-wrapper,tui-tile:where(*[data-tui-version=\"5.7.0\"]):has(tui-tile:where(*[data-tui-version=\"5.7.0\"])._dragged)>.t-wrapper{z-index:1}tui-tile:where(*[data-tui-version=\"5.7.0\"]) [tuiTileHandle]{touch-action:none;-webkit-user-select:none;user-select:none}\n"] }] }] }); class TuiTileService { constructor() { this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID)); this.el = tuiInjectElement(); this.tiles = inject(TuiTilesComponent); this.sub = new Subscription(); this.offset$ = new BehaviorSubject([ Number.NaN, Number.NaN, ]); this.position$ = combineLatest([ this.offset$.pipe(distinctUntilChanged(tuiArrayShallowEquals)), inject(WaResizeObserverService).pipe(startWith(null)), inject(WaMutationObserverService).pipe(startWith(null)), toObservable(this.tiles.order).pipe(debounceTime(0, tuiZonefreeScheduler())), ]).pipe(map(([offset]) => offset)); } init(element) { if (this.isBrowser && element) { this.sub.add(this.position$.subscribe((offset) => { this.setPosition(element, offset); this.setRect(element, offset); })); } else { this.el.style.setProperty('position', 'relative'); } } setOffset(offset) { this.offset$.next(offset); } ngOnDestroy() { this.sub.unsubscribe(); } getRect([left, top]) { const elTop = Number.isNaN(top) ? this.el.offsetTop : top; const elLeft = Number.isNaN(left) ? this.el.offsetLeft : left; const rect = { top: elTop, left: elLeft, width: this.el.clientWidth, height: this.el.clientHeight, right: Number.NaN, bottom: Number.NaN, y: elTop, x: elLeft, }; return { ...rect, toJSON: () => JSON.stringify(rect), }; } setRect({ style }, offset) { const { top, left, width, height } = this.getRect(offset); style.top = tuiPx(top); style.left = tuiPx(left); style.width = tuiPx(width); style.height = tuiPx(height); } setPosition(element, [left]) { if (!Number.isNaN(left)) { element.style.setProperty('position', 'fixed'); element.style.setProperty('transition', 'none'); return; } const { style } = element; const rect = element.getBoundingClientRect(); const host = this.el.getBoundingClientRect(); style.removeProperty('position'); style.removeProperty('transition'); style.removeProperty('top'); style.removeProperty('left'); style.top = tuiPx(rect.top - host.top + this.el.offsetTop); style.left = tuiPx(rect.left - host.left + this.el.offsetLeft); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTileService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTileService, decorators: [{ type: Injectable }] }); class TuiTile { constructor() { this.wrapper = viewChild('wrapper', { read: ElementRef }); this.service = inject(TuiTileService); this.tiles = inject(TuiTilesComponent); this.dragged = signal(false); this.width = input(1); this.height = input(1); this.element = tuiInjectElement(); } onDrag(offset) { const dragged = !Number.isNaN(offset[0]); this.dragged.set(this.dragged() || dragged); this.tiles.element.set(dragged ? this.element : null); this.service.setOffset(offset); if (dragged) { this.tiles.el.classList.add('_dragged'); } else { this.tiles.el.classList.remove('_dragged'); } } ngAfterViewInit() { this.service.init(this.wrapper()?.nativeElement); } ngOnDestroy() { if (this.tiles.element() === this.element) { this.tiles.element.set(null); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTile, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.21", type: TuiTile, isStandalone: true, selector: "tui-tile", inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-tui-version": "5.7.0" }, listeners: { "pointerenter": "tiles.rearrange(element)" }, properties: { "class._dragged": "dragged()", "style.grid-column": "`span var(--tui-width, ${width()})`", "style.grid-row": "`span var(--tui-height, ${height()})`" } }, providers: [TuiTileService], viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div\n #wrapper\n class=\"t-wrapper\"\n (transitionend.self)=\"dragged.set(false)\"\n>\n <ng-content />\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTile, decorators: [{ type: Component, args: [{ selector: 'tui-tile', changeDetection: ChangeDetectionStrategy.OnPush, providers: [TuiTileService], host: { 'data-tui-version': TUI_VERSION, '[class._dragged]': 'dragged()', '[style.grid-column]': '`span var(--tui-width, ${width()})`', '[style.grid-row]': '`span var(--tui-height, ${height()})`', '(pointerenter)': 'tiles.rearrange(element)', }, template: "<div\n #wrapper\n class=\"t-wrapper\"\n (transitionend.self)=\"dragged.set(false)\"\n>\n <ng-content />\n</div>\n" }] }] }); class TuiTileHandle { constructor() { this.doc = inject(DOCUMENT); this.tile = inject(TuiTile); this.x = Number.NaN; this.y = Number.NaN; this.pointerSub = merge(tuiTypedFromEvent(this.doc, 'pointerup'), tuiTypedFromEvent(this.doc, 'pointermove')) .pipe(filter(() => !Number.isNaN(this.x)), takeUntilDestroyed()) .subscribe(({ x, y, type }) => { if (type === 'pointerup') { this.onPointer(); } else { this.tile.onDrag([x - this.x, y - this.y]); } }); } onPointer(x = Number.NaN, y = Number.NaN) { const { left, top } = this.tile.element.getBoundingClientRect(); this.x = x - left; this.y = y - top; this.tile.onDrag([Number.NaN, Number.NaN]); } onStart(event) { const target = tuiGetActualTarget(event); const { x, y, pointerId } = event; if (tuiIsElement(target)) { target.releasePointerCapture(pointerId); } this.onPointer(x, y); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTileHandle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: TuiTileHandle, isStandalone: true, selector: "[tuiTileHandle]", host: { listeners: { "pointerdown.zoneless.prevent": "onStart($event)" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiTileHandle, decorators: [{ type: Directive, args: [{ selector: '[tuiTileHandle]', host: { '(pointerdown.zoneless.prevent)': 'onStart($event)' }, }] }] }); const TuiTiles = [TuiTilesComponent, TuiTile, TuiTileHandle]; /** * Generated bundle index. Do not edit. */ export { TUI_TILES_REORDER, TuiTile, TuiTileHandle, TuiTileService, TuiTiles, TuiTilesComponent, tuiTilesShift, tuiTilesSwap }; //# sourceMappingURL=taiga-ui-kit-components-tiles.mjs.map