@katoid/angular-grid-layout
Version:
Grid Layout with draggable and resizable items for Angular
579 lines • 109 kB
JavaScript
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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