UNPKG

@katoid/angular-grid-layout

Version:

Grid Layout with draggable and resizable items for Angular

579 lines 109 kB
import { ChangeDetectionStrategy, Component, ContentChildren, EventEmitter, Inject, Input, Output, ViewEncapsulation } from '@angular/core'; import { coerceNumberProperty } from './coercion/number-property'; import { KtdGridItemComponent } from './grid-item/grid-item.component'; import { combineLatest, merge, NEVER, Observable, of } from 'rxjs'; import { exhaustMap, map, startWith, switchMap, takeUntil } from 'rxjs/operators'; import { ktdGetGridItemRowHeight, ktdGridItemDragging, ktdGridItemLayoutItemAreEqual, ktdGridItemResizing } from './utils/grid.utils'; import { compact } from './utils/react-grid-layout.utils'; import { GRID_ITEM_GET_RENDER_DATA_TOKEN } from './grid.definitions'; import { ktdPointerUp, ktdPointerClientX, ktdPointerClientY } from './utils/pointer.utils'; import { getMutableClientRect } from './utils/client-rect'; import { ktdGetScrollTotalRelativeDifference$, ktdScrollIfNearElementClientRect$ } from './utils/scroll'; import { coerceBooleanProperty } from './coercion/boolean-property'; import { getTransformTransitionDurationInMs } from './utils/transition-duration'; import { DOCUMENT } from '@angular/common'; import * as i0 from "@angular/core"; import * as i1 from "./grid.service"; function getDragResizeEventData(gridItem, layout) { return { layout, layoutItem: layout.find((item) => item.id === gridItem.id), gridItemRef: gridItem }; } function getColumnWidth(config, width) { const { cols, gap } = config; const widthExcludingGap = width - Math.max((gap * (cols - 1)), 0); return (widthExcludingGap / cols); } function getRowHeightInPixels(config, height) { const { rowHeight, layout, gap } = config; return rowHeight === 'fit' ? ktdGetGridItemRowHeight(layout, height, gap) : rowHeight; } function layoutToRenderItems(config, width, height) { const { layout, gap } = config; const rowHeightInPixels = getRowHeightInPixels(config, height); const itemWidthPerColumn = getColumnWidth(config, width); const renderItems = {}; for (const item of layout) { renderItems[item.id] = { id: item.id, top: item.y * rowHeightInPixels + gap * item.y, left: item.x * itemWidthPerColumn + gap * item.x, width: item.w * itemWidthPerColumn + gap * Math.max(item.w - 1, 0), height: item.h * rowHeightInPixels + gap * Math.max(item.h - 1, 0), }; } return renderItems; } function getGridHeight(layout, rowHeight, gap) { return layout.reduce((acc, cur) => Math.max(acc, (cur.y + cur.h) * rowHeight + Math.max(cur.y + cur.h - 1, 0) * gap), 0); } // eslint-disable-next-line @katoid/prefix-exported-code export function parseRenderItemToPixels(renderItem) { return { id: renderItem.id, top: `${renderItem.top}px`, left: `${renderItem.left}px`, width: `${renderItem.width}px`, height: `${renderItem.height}px` }; } // eslint-disable-next-line @katoid/prefix-exported-code export function __gridItemGetRenderDataFactoryFunc(gridCmp) { return function (id) { return parseRenderItemToPixels(gridCmp.getItemRenderData(id)); }; } export function ktdGridItemGetRenderDataFactoryFunc(gridCmp) { // Workaround explained: https://github.com/ng-packagr/ng-packagr/issues/696#issuecomment-387114613 const resultFunc = __gridItemGetRenderDataFactoryFunc(gridCmp); return resultFunc; } const defaultBackgroundConfig = { borderColor: '#ffa72678', gapColor: 'transparent', rowColor: 'transparent', columnColor: 'transparent', borderWidth: 1, }; export class KtdGridComponent { /** Whether or not to update the internal layout when some dependent property change. */ get compactOnPropsChange() { return this._compactOnPropsChange; } set compactOnPropsChange(value) { this._compactOnPropsChange = coerceBooleanProperty(value); } /** If true, grid items won't change position when being dragged over. Handy when using no compaction */ get preventCollision() { return this._preventCollision; } set preventCollision(value) { this._preventCollision = coerceBooleanProperty(value); } /** Number of CSS pixels that would be scrolled on each 'tick' when auto scroll is performed. */ get scrollSpeed() { return this._scrollSpeed; } set scrollSpeed(value) { this._scrollSpeed = coerceNumberProperty(value, 2); } /** Type of compaction that will be applied to the layout (vertical, horizontal or free). Defaults to 'vertical' */ get compactType() { return this._compactType; } set compactType(val) { this._compactType = val; } /** * Row height as number or as 'fit'. * If rowHeight is a number value, it means that each row would have those css pixels in height. * if rowHeight is 'fit', it means that rows will fit in the height available. If 'fit' value is set, a 'height' should be also provided. */ get rowHeight() { return this._rowHeight; } set rowHeight(val) { this._rowHeight = val === 'fit' ? val : Math.max(1, Math.round(coerceNumberProperty(val))); } /** Number of columns */ get cols() { return this._cols; } set cols(val) { this._cols = Math.max(1, Math.round(coerceNumberProperty(val))); } /** Layout of the grid. Array of all the grid items with its 'id' and position on the grid. */ get layout() { return this._layout; } set layout(layout) { /** * Enhancement: * Only set layout if it's reference has changed and use a boolean to track whenever recalculate the layout on ngOnChanges. * * Why: * The normal use of this lib is having the variable layout in the outer component or in a store, assigning it whenever it changes and * binded in the component with it's input [layout]. In this scenario, we would always calculate one unnecessary change on the layout when * it is re-binded on the input. */ this._layout = layout; } /** Grid gap in css pixels */ get gap() { return this._gap; } set gap(val) { this._gap = Math.max(coerceNumberProperty(val), 0); } /** * If height is a number, fixes the height of the grid to it, recommended when rowHeight = 'fit' is used. * If height is null, height will be automatically set according to its inner grid items. * Defaults to null. * */ get height() { return this._height; } set height(val) { this._height = typeof val === 'number' ? Math.max(val, 0) : null; } get backgroundConfig() { return this._backgroundConfig; } set backgroundConfig(val) { this._backgroundConfig = val; // If there is background configuration, add main grid background class. Grid background class comes with opacity 0. // It is done this way for adding opacity animation and to don't add any styles when grid background is null. const classList = this.elementRef.nativeElement.classList; this._backgroundConfig !== null ? classList.add('ktd-grid-background') : classList.remove('ktd-grid-background'); // Set background visibility this.setGridBackgroundVisible(this._backgroundConfig?.show === 'always'); } get config() { return { cols: this.cols, rowHeight: this.rowHeight, height: this.height, layout: this.layout, preventCollision: this.preventCollision, gap: this.gap, }; } constructor(gridService, elementRef, viewContainerRef, renderer, ngZone, document) { this.gridService = gridService; this.elementRef = elementRef; this.viewContainerRef = viewContainerRef; this.renderer = renderer; this.ngZone = ngZone; this.document = document; /** Emits when layout change */ this.layoutUpdated = new EventEmitter(); /** Emits when drag starts */ this.dragStarted = new EventEmitter(); /** Emits when resize starts */ this.resizeStarted = new EventEmitter(); /** Emits when drag ends */ this.dragEnded = new EventEmitter(); /** Emits when resize ends */ this.resizeEnded = new EventEmitter(); /** Emits when a grid item is being resized and its bounds have changed */ this.gridItemResize = new EventEmitter(); /** * Parent element that contains the scroll. If an string is provided it would search that element by id on the dom. * If no data provided or null autoscroll is not performed. */ this.scrollableParent = null; this._compactOnPropsChange = true; this._preventCollision = false; this._scrollSpeed = 2; this._compactType = 'vertical'; this._rowHeight = 100; this._cols = 6; this._gap = 0; this._height = null; this._backgroundConfig = null; this.subscriptions = []; } ngOnChanges(changes) { if (this.rowHeight === 'fit' && this.height == null) { console.warn(`KtdGridComponent: The @Input() height should not be null when using rowHeight 'fit'`); } let needsCompactLayout = false; let needsRecalculateRenderData = false; // TODO: Does fist change need to be compacted by default? // Compact layout whenever some dependent prop changes. if (changes.compactType || changes.cols || changes.layout) { needsCompactLayout = true; } // Check if wee need to recalculate rendering data. if (needsCompactLayout || changes.rowHeight || changes.height || changes.gap || changes.backgroundConfig) { needsRecalculateRenderData = true; } // Only compact layout if lib user has provided it. Lib users that want to save/store always the same layout as it is represented (compacted) // can use KtdCompactGrid utility and pre-compact the layout. This is the recommended behaviour for always having a the same layout on this component // and the ones that uses it. if (needsCompactLayout && this.compactOnPropsChange) { this.compactLayout(); } if (needsRecalculateRenderData) { this.calculateRenderData(); } } ngAfterContentInit() { this.initSubscriptions(); } ngAfterContentChecked() { this.render(); } resize() { this.calculateRenderData(); this.render(); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } compactLayout() { this.layout = compact(this.layout, this.compactType, this.cols); } getItemsRenderData() { return { ...this._gridItemsRenderData }; } getItemRenderData(itemId) { return this._gridItemsRenderData[itemId]; } calculateRenderData() { const clientRect = this.elementRef.nativeElement.getBoundingClientRect(); this.gridCurrentHeight = this.height ?? (this.rowHeight === 'fit' ? clientRect.height : getGridHeight(this.layout, this.rowHeight, this.gap)); this._gridItemsRenderData = layoutToRenderItems(this.config, clientRect.width, this.gridCurrentHeight); // Set Background CSS variables this.setBackgroundCssVariables(getRowHeightInPixels(this.config, this.gridCurrentHeight)); } render() { this.renderer.setStyle(this.elementRef.nativeElement, 'height', `${this.gridCurrentHeight}px`); this.updateGridItemsStyles(); } setBackgroundCssVariables(rowHeight) { const style = this.elementRef.nativeElement.style; if (this._backgroundConfig) { // structure style.setProperty('--gap', this.gap + 'px'); style.setProperty('--row-height', rowHeight + 'px'); style.setProperty('--columns', `${this.cols}`); style.setProperty('--border-width', (this._backgroundConfig.borderWidth ?? defaultBackgroundConfig.borderWidth) + 'px'); // colors style.setProperty('--border-color', this._backgroundConfig.borderColor ?? defaultBackgroundConfig.borderColor); style.setProperty('--gap-color', this._backgroundConfig.gapColor ?? defaultBackgroundConfig.gapColor); style.setProperty('--row-color', this._backgroundConfig.rowColor ?? defaultBackgroundConfig.rowColor); style.setProperty('--column-color', this._backgroundConfig.columnColor ?? defaultBackgroundConfig.columnColor); } else { style.removeProperty('--gap'); style.removeProperty('--row-height'); style.removeProperty('--columns'); style.removeProperty('--border-width'); style.removeProperty('--border-color'); style.removeProperty('--gap-color'); style.removeProperty('--row-color'); style.removeProperty('--column-color'); } } updateGridItemsStyles() { this._gridItems.forEach(item => { const gridItemRenderData = this._gridItemsRenderData[item.id]; if (gridItemRenderData == null) { console.error(`Couldn\'t find the specified grid item for the id: ${item.id}`); } else { item.setStyles(parseRenderItemToPixels(gridItemRenderData)); } }); } setGridBackgroundVisible(visible) { const classList = this.elementRef.nativeElement.classList; visible ? classList.add('ktd-grid-background-visible') : classList.remove('ktd-grid-background-visible'); } initSubscriptions() { this.subscriptions = [ this._gridItems.changes.pipe(startWith(this._gridItems), switchMap((gridItems) => { return merge(...gridItems.map((gridItem) => gridItem.dragStart$.pipe(map((event) => ({ event, gridItem, type: 'drag' })))), ...gridItems.map((gridItem) => gridItem.resizeStart$.pipe(map((event) => ({ event, gridItem, type: 'resize' }))))).pipe(exhaustMap(({ event, gridItem, type }) => { // Emit drag or resize start events. Ensure that is start event is inside the zone. this.ngZone.run(() => (type === 'drag' ? this.dragStarted : this.resizeStarted).emit(getDragResizeEventData(gridItem, this.layout))); this.setGridBackgroundVisible(this._backgroundConfig?.show === 'whenDragging' || this._backgroundConfig?.show === 'always'); // Perform drag sequence return this.performDragSequence$(gridItem, event, type).pipe(map((layout) => ({ layout, gridItem, type }))); })); })).subscribe(({ layout, gridItem, type }) => { this.layout = layout; // Calculate new rendering data given the new layout. this.calculateRenderData(); // Emit drag or resize end events. (type === 'drag' ? this.dragEnded : this.resizeEnded).emit(getDragResizeEventData(gridItem, layout)); // Notify that the layout has been updated. this.layoutUpdated.emit(layout); this.setGridBackgroundVisible(this._backgroundConfig?.show === 'always'); }) ]; } /** * Perform a general grid drag action, from start to end. A general grid drag action basically includes creating the placeholder element and adding * some class animations. calcNewStateFunc needs to be provided in order to calculate the new state of the layout. * @param gridItem that is been dragged * @param pointerDownEvent event (mousedown or touchdown) where the user initiated the drag * @param calcNewStateFunc function that return the new layout state and the drag element position */ performDragSequence$(gridItem, pointerDownEvent, type) { return new Observable((observer) => { // Retrieve grid (parent) and gridItem (draggedElem) client rects. const gridElemClientRect = getMutableClientRect(this.elementRef.nativeElement); const dragElemClientRect = getMutableClientRect(gridItem.elementRef.nativeElement); const scrollableParent = typeof this.scrollableParent === 'string' ? this.document.getElementById(this.scrollableParent) : this.scrollableParent; this.renderer.addClass(gridItem.elementRef.nativeElement, 'no-transitions'); this.renderer.addClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-dragging'); const placeholderClientRect = { ...dragElemClientRect, left: dragElemClientRect.left - gridElemClientRect.left, top: dragElemClientRect.top - gridElemClientRect.top }; this.createPlaceholderElement(placeholderClientRect, gridItem.placeholder); let newLayout; // TODO (enhancement): consider move this 'side effect' observable inside the main drag loop. // - Pros are that we would not repeat subscriptions and takeUntil would shut down observables at the same time. // - Cons are that moving this functionality as a side effect inside the main drag loop would be confusing. const scrollSubscription = this.ngZone.runOutsideAngular(() => (!scrollableParent ? NEVER : this.gridService.mouseOrTouchMove$(this.document).pipe(map((event) => ({ pointerX: ktdPointerClientX(event), pointerY: ktdPointerClientY(event) })), ktdScrollIfNearElementClientRect$(scrollableParent, { scrollStep: this.scrollSpeed }))).pipe(takeUntil(ktdPointerUp(this.document))).subscribe()); /** * Main subscription, it listens for 'pointer move' and 'scroll' events and recalculates the layout on each emission */ const subscription = this.ngZone.runOutsideAngular(() => merge(combineLatest([ this.gridService.mouseOrTouchMove$(this.document), ...(!scrollableParent ? [of({ top: 0, left: 0 })] : [ ktdGetScrollTotalRelativeDifference$(scrollableParent).pipe(startWith({ top: 0, left: 0 }) // Force first emission to allow CombineLatest to emit even no scroll event has occurred ) ]) ])).pipe(takeUntil(ktdPointerUp(this.document))).subscribe(([pointerDragEvent, scrollDifference]) => { pointerDragEvent.preventDefault(); /** * Set the new layout to be the layout in which the calcNewStateFunc would be executed. * NOTE: using the mutated layout is the way to go by 'react-grid-layout' utils. If we don't use the previous layout, * some utilities from 'react-grid-layout' would not work as expected. */ const currentLayout = newLayout || this.layout; // Get the correct newStateFunc depending on if we are dragging or resizing const calcNewStateFunc = type === 'drag' ? ktdGridItemDragging : ktdGridItemResizing; const { layout, draggedItemPos } = calcNewStateFunc(gridItem, { layout: currentLayout, rowHeight: this.rowHeight, height: this.height, cols: this.cols, preventCollision: this.preventCollision, gap: this.gap, }, this.compactType, { pointerDownEvent, pointerDragEvent, gridElemClientRect, dragElemClientRect, scrollDifference }); newLayout = layout; this.gridCurrentHeight = this.height ?? (this.rowHeight === 'fit' ? gridElemClientRect.height : getGridHeight(newLayout, this.rowHeight, this.gap)); this._gridItemsRenderData = layoutToRenderItems({ cols: this.cols, rowHeight: this.rowHeight, height: this.height, layout: newLayout, preventCollision: this.preventCollision, gap: this.gap, }, gridElemClientRect.width, gridElemClientRect.height); const newGridItemRenderData = { ...this._gridItemsRenderData[gridItem.id] }; const placeholderStyles = parseRenderItemToPixels(newGridItemRenderData); // Put the real final position to the placeholder element this.placeholder.style.width = placeholderStyles.width; this.placeholder.style.height = placeholderStyles.height; this.placeholder.style.transform = `translateX(${placeholderStyles.left}) translateY(${placeholderStyles.top})`; // modify the position of the dragged item to be the once we want (for example the mouse position or whatever) this._gridItemsRenderData[gridItem.id] = { ...draggedItemPos, id: this._gridItemsRenderData[gridItem.id].id }; this.setBackgroundCssVariables(this.rowHeight === 'fit' ? ktdGetGridItemRowHeight(newLayout, gridElemClientRect.height, this.gap) : this.rowHeight); this.render(); // If we are performing a resize, and bounds have changed, emit event. // NOTE: Only emit on resize for now. Use case for normal drag is not justified for now. Emitting on resize is, since we may want to re-render the grid item or the placeholder in order to fit the new bounds. if (type === 'resize') { const prevGridItem = currentLayout.find(item => item.id === gridItem.id); const newGridItem = newLayout.find(item => item.id === gridItem.id); // Check if item resized has changed, if so, emit resize change event if (!ktdGridItemLayoutItemAreEqual(prevGridItem, newGridItem)) { this.gridItemResize.emit({ width: newGridItemRenderData.width, height: newGridItemRenderData.height, gridItemRef: getDragResizeEventData(gridItem, newLayout).gridItemRef }); } } }, (error) => observer.error(error), () => { this.ngZone.run(() => { // Remove drag classes this.renderer.removeClass(gridItem.elementRef.nativeElement, 'no-transitions'); this.renderer.removeClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-dragging'); this.addGridItemAnimatingClass(gridItem).subscribe(); // Consider destroying the placeholder after the animation has finished. this.destroyPlaceholder(); if (newLayout) { // TODO: newLayout should already be pruned. If not, it should have type Layout, not KtdGridLayout as it is now. // Prune react-grid-layout compact extra properties. observer.next(newLayout.map(item => ({ id: item.id, x: item.x, y: item.y, w: item.w, h: item.h, minW: item.minW, minH: item.minH, maxW: item.maxW, maxH: item.maxH, }))); } else { // TODO: Need we really to emit if there is no layout change but drag started and ended? observer.next(this.layout); } observer.complete(); }); })); return () => { scrollSubscription.unsubscribe(); subscription.unsubscribe(); }; }); } /** * It adds the `ktd-grid-item-animating` class and removes it when the animated transition is complete. * This function is meant to be executed when the drag has ended. * @param gridItem that has been dragged */ addGridItemAnimatingClass(gridItem) { return new Observable(observer => { const duration = getTransformTransitionDurationInMs(gridItem.elementRef.nativeElement); if (duration === 0) { observer.next(); observer.complete(); return; } this.renderer.addClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-animating'); const handler = ((event) => { if (!event || (event.target === gridItem.elementRef.nativeElement && event.propertyName === 'transform')) { this.renderer.removeClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-animating'); removeEventListener(); clearTimeout(timeout); observer.next(); observer.complete(); } }); // If a transition is short enough, the browser might not fire the `transitionend` event. // Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll // fire if the transition hasn't completed when it was supposed to. const timeout = setTimeout(handler, duration * 1.5); const removeEventListener = this.renderer.listen(gridItem.elementRef.nativeElement, 'transitionend', handler); }); } /** Creates placeholder element */ createPlaceholderElement(clientRect, gridItemPlaceholder) { this.placeholder = this.renderer.createElement('div'); this.placeholder.style.width = `${clientRect.width}px`; this.placeholder.style.height = `${clientRect.height}px`; this.placeholder.style.transform = `translateX(${clientRect.left}px) translateY(${clientRect.top}px)`; this.placeholder.classList.add('ktd-grid-item-placeholder'); this.renderer.appendChild(this.elementRef.nativeElement, this.placeholder); // Create and append custom placeholder if provided. // Important: Append it after creating & appending the container placeholder. This way we ensure parent bounds are set when creating the embeddedView. if (gridItemPlaceholder) { this.placeholderRef = this.viewContainerRef.createEmbeddedView(gridItemPlaceholder.templateRef, gridItemPlaceholder.data); this.placeholderRef.rootNodes.forEach(node => this.placeholder.appendChild(node)); this.placeholderRef.detectChanges(); } else { this.placeholder.classList.add('ktd-grid-item-placeholder-default'); } } /** Destroys the placeholder element and its ViewRef. */ destroyPlaceholder() { this.placeholder?.remove(); this.placeholderRef?.destroy(); this.placeholder = this.placeholderRef = null; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KtdGridComponent, deps: [{ token: i1.KtdGridService }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: KtdGridComponent, isStandalone: true, selector: "ktd-grid", inputs: { scrollableParent: "scrollableParent", compactOnPropsChange: "compactOnPropsChange", preventCollision: "preventCollision", scrollSpeed: "scrollSpeed", compactType: "compactType", rowHeight: "rowHeight", cols: "cols", layout: "layout", gap: "gap", height: "height", backgroundConfig: "backgroundConfig" }, outputs: { layoutUpdated: "layoutUpdated", dragStarted: "dragStarted", resizeStarted: "resizeStarted", dragEnded: "dragEnded", resizeEnded: "resizeEnded", gridItemResize: "gridItemResize" }, providers: [ { provide: GRID_ITEM_GET_RENDER_DATA_TOKEN, useFactory: ktdGridItemGetRenderDataFactoryFunc, deps: [KtdGridComponent] } ], queries: [{ propertyName: "_gridItems", predicate: KtdGridItemComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-content></ng-content>", styles: ["ktd-grid{display:block;position:relative;width:100%}ktd-grid.ktd-grid-background:before{content:\"\";border:none;position:absolute;inset:0;z-index:0;transition:opacity .2s;opacity:0;background-image:repeating-linear-gradient(var(--border-color) 0 var(--border-width),var(--row-color) var(--border-width) calc(var(--row-height) - var(--border-width)),var(--border-color) calc(var(--row-height) - var(--border-width)) calc(var(--row-height)),var(--gap-color) calc(var(--row-height)) calc(var(--row-height) + var(--gap))),repeating-linear-gradient(90deg,var(--border-color) 0 var(--border-width),var(--column-color) var(--border-width) calc(100% - (var(--border-width) + var(--gap))),var(--border-color) calc(100% - (var(--border-width) + var(--gap))) calc(100% - var(--gap)),var(--gap-color) calc(100% - var(--gap)) 100%);background-size:calc((100% + var(--gap)) / var(--columns)) calc(var(--row-height) + var(--gap));background-position:0 0}ktd-grid.ktd-grid-background.ktd-grid-background-visible:before{opacity:1}ktd-grid ktd-grid-item.ktd-grid-item-dragging,ktd-grid ktd-grid-item.ktd-grid-item-animating{z-index:1000}ktd-grid ktd-grid-item.no-transitions{transition:none!important}ktd-grid .ktd-grid-item-placeholder{position:absolute;z-index:0;transition-property:transform;transition:all .15s ease}ktd-grid .ktd-grid-item-placeholder-default{background-color:#8b0000;opacity:.6}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KtdGridComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'ktd-grid', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: GRID_ITEM_GET_RENDER_DATA_TOKEN, useFactory: ktdGridItemGetRenderDataFactoryFunc, deps: [KtdGridComponent] } ], template: "<ng-content></ng-content>", styles: ["ktd-grid{display:block;position:relative;width:100%}ktd-grid.ktd-grid-background:before{content:\"\";border:none;position:absolute;inset:0;z-index:0;transition:opacity .2s;opacity:0;background-image:repeating-linear-gradient(var(--border-color) 0 var(--border-width),var(--row-color) var(--border-width) calc(var(--row-height) - var(--border-width)),var(--border-color) calc(var(--row-height) - var(--border-width)) calc(var(--row-height)),var(--gap-color) calc(var(--row-height)) calc(var(--row-height) + var(--gap))),repeating-linear-gradient(90deg,var(--border-color) 0 var(--border-width),var(--column-color) var(--border-width) calc(100% - (var(--border-width) + var(--gap))),var(--border-color) calc(100% - (var(--border-width) + var(--gap))) calc(100% - var(--gap)),var(--gap-color) calc(100% - var(--gap)) 100%);background-size:calc((100% + var(--gap)) / var(--columns)) calc(var(--row-height) + var(--gap));background-position:0 0}ktd-grid.ktd-grid-background.ktd-grid-background-visible:before{opacity:1}ktd-grid ktd-grid-item.ktd-grid-item-dragging,ktd-grid ktd-grid-item.ktd-grid-item-animating{z-index:1000}ktd-grid ktd-grid-item.no-transitions{transition:none!important}ktd-grid .ktd-grid-item-placeholder{position:absolute;z-index:0;transition-property:transform;transition:all .15s ease}ktd-grid .ktd-grid-item-placeholder-default{background-color:#8b0000;opacity:.6}\n"] }] }], ctorParameters: function () { return [{ type: i1.KtdGridService }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { _gridItems: [{ type: ContentChildren, args: [KtdGridItemComponent, { descendants: true }] }], layoutUpdated: [{ type: Output }], dragStarted: [{ type: Output }], resizeStarted: [{ type: Output }], dragEnded: [{ type: Output }], resizeEnded: [{ type: Output }], gridItemResize: [{ type: Output }], scrollableParent: [{ type: Input }], compactOnPropsChange: [{ type: Input }], preventCollision: [{ type: Input }], scrollSpeed: [{ type: Input }], compactType: [{ type: Input }], rowHeight: [{ type: Input }], cols: [{ type: Input }], layout: [{ type: Input }], gap: [{ type: Input }], height: [{ type: Input }], backgroundConfig: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWdyaWQtbGF5b3V0L3NyYy9saWIvZ3JpZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWdyaWQtbGF5b3V0L3NyYy9saWIvZ3JpZC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ29DLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQStCLFlBQVksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUN0SCxNQUFNLEVBQXlELGlCQUFpQixFQUNqSCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsb0JBQW9CLEVBQWUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN2RSxPQUFPLEVBQUUsYUFBYSxFQUFTLEtBQUssRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFZLEVBQUUsRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDbEcsT0FBTyxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNsRixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsbUJBQW1CLEVBQUUsNkJBQTZCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0SSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDMUQsT0FBTyxFQUNILCtCQUErQixFQUNsQyxNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUczRixPQUFPLEVBQUUsb0JBQW9CLEVBQWlCLE1BQU0scUJBQXFCLENBQUM7QUFDMUUsT0FBTyxF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