@taiga-ui/kit
Version:
Taiga UI Angular main components kit
272 lines (263 loc) • 15.6 kB
JavaScript
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