angular-resizable-element
Version:
An angular 15.0+ directive that allows an element to be dragged and resized
774 lines (765 loc) • 31.9 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, PLATFORM_ID, Directive, Inject, Input, Output, Optional, NgModule } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Subject, merge, Observable, fromEvent } from 'rxjs';
import { tap, share, mergeMap, take, map, pairwise, filter, takeUntil } from 'rxjs/operators';
/**
* @hidden
*/
const IS_TOUCH_DEVICE = (() => {
// In case we're in Node.js environment.
if (typeof window === 'undefined') {
return false;
}
else {
return ('ontouchstart' in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints >
0);
}
})();
/** Creates a deep clone of an element. */
function deepCloneNode(node) {
const clone = node.cloneNode(true);
const descendantsWithId = clone.querySelectorAll('[id]');
const nodeName = node.nodeName.toLowerCase();
// Remove the `id` to avoid having multiple elements with the same id on the page.
clone.removeAttribute('id');
descendantsWithId.forEach((descendant) => {
descendant.removeAttribute('id');
});
if (nodeName === 'canvas') {
transferCanvasData(node, clone);
}
else if (nodeName === 'input' ||
nodeName === 'select' ||
nodeName === 'textarea') {
transferInputData(node, clone);
}
transferData('canvas', node, clone, transferCanvasData);
transferData('input, textarea, select', node, clone, transferInputData);
return clone;
}
/** Matches elements between an element and its clone and allows for their data to be cloned. */
function transferData(selector, node, clone, callback) {
const descendantElements = node.querySelectorAll(selector);
if (descendantElements.length) {
const cloneElements = clone.querySelectorAll(selector);
for (let i = 0; i < descendantElements.length; i++) {
callback(descendantElements[i], cloneElements[i]);
}
}
}
// Counter for unique cloned radio button names.
let cloneUniqueId = 0;
/** Transfers the data of one input element to another. */
function transferInputData(source, clone) {
// Browsers throw an error when assigning the value of a file input programmatically.
if (clone.type !== 'file') {
clone.value = source.value;
}
// Radio button `name` attributes must be unique for radio button groups
// otherwise original radio buttons can lose their checked state
// once the clone is inserted in the DOM.
if (clone.type === 'radio' && clone.name) {
clone.name = `mat-clone-${clone.name}-${cloneUniqueId++}`;
}
}
/** Transfers the data of one canvas element to another. */
function transferCanvasData(source, clone) {
const context = clone.getContext('2d');
if (context) {
// In some cases `drawImage` can throw (e.g. if the canvas size is 0x0).
// We can't do much about it so just ignore the error.
try {
context.drawImage(source, 0, 0);
}
catch (_a) { }
}
}
function getNewBoundingRectangle(startingRect, edges, clientX, clientY) {
const newBoundingRect = {
top: startingRect.top,
bottom: startingRect.bottom,
left: startingRect.left,
right: startingRect.right,
};
if (edges.top) {
newBoundingRect.top += clientY;
}
if (edges.bottom) {
newBoundingRect.bottom += clientY;
}
if (edges.left) {
newBoundingRect.left += clientX;
}
if (edges.right) {
newBoundingRect.right += clientX;
}
newBoundingRect.height = newBoundingRect.bottom - newBoundingRect.top;
newBoundingRect.width = newBoundingRect.right - newBoundingRect.left;
return newBoundingRect;
}
function getElementRect(element, ghostElementPositioning) {
let translateX = 0;
let translateY = 0;
const style = element.nativeElement.style;
const transformProperties = [
'transform',
'-ms-transform',
'-moz-transform',
'-o-transform',
];
const transform = transformProperties
.map((property) => style[property])
.find((value) => !!value);
if (transform && transform.includes('translate')) {
translateX = transform.replace(/.*translate3?d?\((-?[0-9]*)px, (-?[0-9]*)px.*/, '$1');
translateY = transform.replace(/.*translate3?d?\((-?[0-9]*)px, (-?[0-9]*)px.*/, '$2');
}
if (ghostElementPositioning === 'absolute') {
return {
height: element.nativeElement.offsetHeight,
width: element.nativeElement.offsetWidth,
top: element.nativeElement.offsetTop - translateY,
bottom: element.nativeElement.offsetHeight +
element.nativeElement.offsetTop -
translateY,
left: element.nativeElement.offsetLeft - translateX,
right: element.nativeElement.offsetWidth +
element.nativeElement.offsetLeft -
translateX,
};
}
else {
const boundingRect = element.nativeElement.getBoundingClientRect();
return {
height: boundingRect.height,
width: boundingRect.width,
top: boundingRect.top - translateY,
bottom: boundingRect.bottom - translateY,
left: boundingRect.left - translateX,
right: boundingRect.right - translateX,
scrollTop: element.nativeElement.scrollTop,
scrollLeft: element.nativeElement.scrollLeft,
};
}
}
const DEFAULT_RESIZE_CURSORS = Object.freeze({
topLeft: 'nw-resize',
topRight: 'ne-resize',
bottomLeft: 'sw-resize',
bottomRight: 'se-resize',
leftOrRight: 'col-resize',
topOrBottom: 'row-resize',
});
function getResizeCursor(edges, cursors) {
if (edges.left && edges.top) {
return cursors.topLeft;
}
else if (edges.right && edges.top) {
return cursors.topRight;
}
else if (edges.left && edges.bottom) {
return cursors.bottomLeft;
}
else if (edges.right && edges.bottom) {
return cursors.bottomRight;
}
else if (edges.left || edges.right) {
return cursors.leftOrRight;
}
else if (edges.top || edges.bottom) {
return cursors.topOrBottom;
}
else {
return '';
}
}
function getEdgesDiff({ edges, initialRectangle, newRectangle, }) {
const edgesDiff = {};
Object.keys(edges).forEach((edge) => {
edgesDiff[edge] = (newRectangle[edge] || 0) - (initialRectangle[edge] || 0);
});
return edgesDiff;
}
const RESIZE_ACTIVE_CLASS = 'resize-active';
const RESIZE_GHOST_ELEMENT_CLASS = 'resize-ghost-element';
const MOUSE_MOVE_THROTTLE_MS = 50;
/**
* Place this on an element to make it resizable. For example:
*
* ```html
* <div
* mwlResizable
* [resizeEdges]="{bottom: true, right: true, top: true, left: true}"
* [enableGhostResize]="true">
* </div>
* ```
* Or in case they are sibling elements:
* ```html
* <div mwlResizable #resizableElement="mwlResizable"></div>
* <div mwlResizeHandle [resizableContainer]="resizableElement" [resizeEdges]="{bottom: true, right: true}"></div>
* ```
*/
class ResizableDirective {
/**
* @hidden
*/
constructor(platformId, renderer, elm, zone) {
this.platformId = platformId;
this.renderer = renderer;
this.elm = elm;
this.zone = zone;
/**
* Set to `true` to enable a temporary resizing effect of the element in between the `resizeStart` and `resizeEnd` events.
*/
this.enableGhostResize = false;
/**
* A snap grid that resize events will be locked to.
*
* e.g. to only allow the element to be resized every 10px set it to `{left: 10, right: 10}`
*/
this.resizeSnapGrid = {};
/**
* The mouse cursors that will be set on the resize edges
*/
this.resizeCursors = DEFAULT_RESIZE_CURSORS;
/**
* Define the positioning of the ghost element (can be fixed or absolute)
*/
this.ghostElementPositioning = 'fixed';
/**
* Allow elements to be resized to negative dimensions
*/
this.allowNegativeResizes = false;
/**
* The mouse move throttle in milliseconds, default: 50 ms
*/
this.mouseMoveThrottleMS = MOUSE_MOVE_THROTTLE_MS;
/**
* Called when the mouse is pressed and a resize event is about to begin. `$event` is a `ResizeEvent` object.
*/
this.resizeStart = new EventEmitter();
/**
* Called as the mouse is dragged after a resize event has begun. `$event` is a `ResizeEvent` object.
*/
this.resizing = new EventEmitter();
/**
* Called after the mouse is released after a resize event. `$event` is a `ResizeEvent` object.
*/
this.resizeEnd = new EventEmitter();
/**
* @hidden
*/
this.mouseup = new Subject();
/**
* @hidden
*/
this.mousedown = new Subject();
/**
* @hidden
*/
this.mousemove = new Subject();
this.destroy$ = new Subject();
this.pointerEventListeners = PointerEventListeners.getInstance(renderer, zone);
}
/**
* @hidden
*/
ngOnInit() {
const mousedown$ = merge(this.pointerEventListeners.pointerDown, this.mousedown);
const mousemove$ = merge(this.pointerEventListeners.pointerMove, this.mousemove).pipe(tap(({ event }) => {
if (currentResize && event.cancelable) {
event.preventDefault();
}
}), share());
const mouseup$ = merge(this.pointerEventListeners.pointerUp, this.mouseup);
let currentResize;
const removeGhostElement = () => {
if (currentResize && currentResize.clonedNode) {
this.elm.nativeElement.parentElement.removeChild(currentResize.clonedNode);
this.renderer.setStyle(this.elm.nativeElement, 'visibility', 'inherit');
}
};
const getResizeCursors = () => {
return Object.assign(Object.assign({}, DEFAULT_RESIZE_CURSORS), this.resizeCursors);
};
const mousedrag = mousedown$
.pipe(mergeMap((startCoords) => {
function getDiff(moveCoords) {
return {
clientX: moveCoords.clientX - startCoords.clientX,
clientY: moveCoords.clientY - startCoords.clientY,
};
}
const getSnapGrid = () => {
const snapGrid = { x: 1, y: 1 };
if (currentResize) {
if (this.resizeSnapGrid.left && currentResize.edges.left) {
snapGrid.x = +this.resizeSnapGrid.left;
}
else if (this.resizeSnapGrid.right &&
currentResize.edges.right) {
snapGrid.x = +this.resizeSnapGrid.right;
}
if (this.resizeSnapGrid.top && currentResize.edges.top) {
snapGrid.y = +this.resizeSnapGrid.top;
}
else if (this.resizeSnapGrid.bottom &&
currentResize.edges.bottom) {
snapGrid.y = +this.resizeSnapGrid.bottom;
}
}
return snapGrid;
};
function getGrid(coords, snapGrid) {
return {
x: Math.ceil(coords.clientX / snapGrid.x),
y: Math.ceil(coords.clientY / snapGrid.y),
};
}
return merge(mousemove$.pipe(take(1)).pipe(map((coords) => [, coords])), mousemove$.pipe(pairwise()))
.pipe(map(([previousCoords, newCoords]) => {
return [
previousCoords ? getDiff(previousCoords) : previousCoords,
getDiff(newCoords),
];
}))
.pipe(filter(([previousCoords, newCoords]) => {
if (!previousCoords) {
return true;
}
const snapGrid = getSnapGrid();
const previousGrid = getGrid(previousCoords, snapGrid);
const newGrid = getGrid(newCoords, snapGrid);
return (previousGrid.x !== newGrid.x || previousGrid.y !== newGrid.y);
}))
.pipe(map(([, newCoords]) => {
const snapGrid = getSnapGrid();
return {
clientX: Math.round(newCoords.clientX / snapGrid.x) * snapGrid.x,
clientY: Math.round(newCoords.clientY / snapGrid.y) * snapGrid.y,
};
}))
.pipe(takeUntil(merge(mouseup$, mousedown$)));
}))
.pipe(filter(() => !!currentResize));
mousedrag
.pipe(map(({ clientX, clientY }) => {
return getNewBoundingRectangle(currentResize.startingRect, currentResize.edges, clientX, clientY);
}))
.pipe(filter((newBoundingRect) => {
return (this.allowNegativeResizes ||
!!(newBoundingRect.height &&
newBoundingRect.width &&
newBoundingRect.height > 0 &&
newBoundingRect.width > 0));
}))
.pipe(filter((newBoundingRect) => {
return this.validateResize
? this.validateResize({
rectangle: newBoundingRect,
edges: getEdgesDiff({
edges: currentResize.edges,
initialRectangle: currentResize.startingRect,
newRectangle: newBoundingRect,
}),
})
: true;
}), takeUntil(this.destroy$))
.subscribe((newBoundingRect) => {
if (currentResize && currentResize.clonedNode) {
this.renderer.setStyle(currentResize.clonedNode, 'height', `${newBoundingRect.height}px`);
this.renderer.setStyle(currentResize.clonedNode, 'width', `${newBoundingRect.width}px`);
this.renderer.setStyle(currentResize.clonedNode, 'top', `${newBoundingRect.top}px`);
this.renderer.setStyle(currentResize.clonedNode, 'left', `${newBoundingRect.left}px`);
}
if (this.resizing.observers.length > 0) {
this.zone.run(() => {
this.resizing.emit({
edges: getEdgesDiff({
edges: currentResize.edges,
initialRectangle: currentResize.startingRect,
newRectangle: newBoundingRect,
}),
rectangle: newBoundingRect,
});
});
}
currentResize.currentRect = newBoundingRect;
});
mousedown$
.pipe(map(({ edges }) => {
return edges || {};
}), filter((edges) => {
return Object.keys(edges).length > 0;
}), takeUntil(this.destroy$))
.subscribe((edges) => {
if (currentResize) {
removeGhostElement();
}
const startingRect = getElementRect(this.elm, this.ghostElementPositioning);
currentResize = {
edges,
startingRect,
currentRect: startingRect,
};
const resizeCursors = getResizeCursors();
const cursor = getResizeCursor(currentResize.edges, resizeCursors);
this.renderer.setStyle(document.body, 'cursor', cursor);
this.setElementClass(this.elm, RESIZE_ACTIVE_CLASS, true);
if (this.enableGhostResize) {
currentResize.clonedNode = deepCloneNode(this.elm.nativeElement);
this.elm.nativeElement.parentElement.appendChild(currentResize.clonedNode);
this.renderer.setStyle(this.elm.nativeElement, 'visibility', 'hidden');
this.renderer.setStyle(currentResize.clonedNode, 'position', this.ghostElementPositioning);
this.renderer.setStyle(currentResize.clonedNode, 'left', `${currentResize.startingRect.left}px`);
this.renderer.setStyle(currentResize.clonedNode, 'top', `${currentResize.startingRect.top}px`);
this.renderer.setStyle(currentResize.clonedNode, 'height', `${currentResize.startingRect.height}px`);
this.renderer.setStyle(currentResize.clonedNode, 'width', `${currentResize.startingRect.width}px`);
this.renderer.setStyle(currentResize.clonedNode, 'cursor', getResizeCursor(currentResize.edges, resizeCursors));
this.renderer.addClass(currentResize.clonedNode, RESIZE_GHOST_ELEMENT_CLASS);
currentResize.clonedNode.scrollTop = currentResize.startingRect
.scrollTop;
currentResize.clonedNode.scrollLeft = currentResize.startingRect
.scrollLeft;
}
if (this.resizeStart.observers.length > 0) {
this.zone.run(() => {
this.resizeStart.emit({
edges: getEdgesDiff({
edges,
initialRectangle: startingRect,
newRectangle: startingRect,
}),
rectangle: getNewBoundingRectangle(startingRect, {}, 0, 0),
});
});
}
});
mouseup$.pipe(takeUntil(this.destroy$)).subscribe(() => {
if (currentResize) {
this.renderer.removeClass(this.elm.nativeElement, RESIZE_ACTIVE_CLASS);
this.renderer.setStyle(document.body, 'cursor', '');
this.renderer.setStyle(this.elm.nativeElement, 'cursor', '');
if (this.resizeEnd.observers.length > 0) {
this.zone.run(() => {
this.resizeEnd.emit({
edges: getEdgesDiff({
edges: currentResize.edges,
initialRectangle: currentResize.startingRect,
newRectangle: currentResize.currentRect,
}),
rectangle: currentResize.currentRect,
});
});
}
removeGhostElement();
currentResize = null;
}
});
}
/**
* @hidden
*/
ngOnDestroy() {
// browser check for angular universal, because it doesn't know what document is
if (isPlatformBrowser(this.platformId)) {
this.renderer.setStyle(document.body, 'cursor', '');
}
this.mousedown.complete();
this.mouseup.complete();
this.mousemove.complete();
this.destroy$.next();
}
setElementClass(elm, name, add) {
if (add) {
this.renderer.addClass(elm.nativeElement, name);
}
else {
this.renderer.removeClass(elm.nativeElement, name);
}
}
}
ResizableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableDirective, deps: [{ token: PLATFORM_ID }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
ResizableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.3", type: ResizableDirective, selector: "[mwlResizable]", inputs: { validateResize: "validateResize", enableGhostResize: "enableGhostResize", resizeSnapGrid: "resizeSnapGrid", resizeCursors: "resizeCursors", ghostElementPositioning: "ghostElementPositioning", allowNegativeResizes: "allowNegativeResizes", mouseMoveThrottleMS: "mouseMoveThrottleMS" }, outputs: { resizeStart: "resizeStart", resizing: "resizing", resizeEnd: "resizeEnd" }, exportAs: ["mwlResizable"], ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlResizable]',
exportAs: 'mwlResizable',
}]
}], ctorParameters: function () {
return [{ type: undefined, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }];
}, propDecorators: { validateResize: [{
type: Input
}], enableGhostResize: [{
type: Input
}], resizeSnapGrid: [{
type: Input
}], resizeCursors: [{
type: Input
}], ghostElementPositioning: [{
type: Input
}], allowNegativeResizes: [{
type: Input
}], mouseMoveThrottleMS: [{
type: Input
}], resizeStart: [{
type: Output
}], resizing: [{
type: Output
}], resizeEnd: [{
type: Output
}] } });
class PointerEventListeners {
constructor(renderer, zone) {
this.pointerDown = new Observable((observer) => {
let unsubscribeMouseDown;
let unsubscribeTouchStart;
zone.runOutsideAngular(() => {
unsubscribeMouseDown = renderer.listen('document', 'mousedown', (event) => {
observer.next({
clientX: event.clientX,
clientY: event.clientY,
event,
});
});
if (IS_TOUCH_DEVICE) {
unsubscribeTouchStart = renderer.listen('document', 'touchstart', (event) => {
observer.next({
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
event,
});
});
}
});
return () => {
unsubscribeMouseDown();
if (IS_TOUCH_DEVICE) {
unsubscribeTouchStart();
}
};
}).pipe(share());
this.pointerMove = new Observable((observer) => {
let unsubscribeMouseMove;
let unsubscribeTouchMove;
zone.runOutsideAngular(() => {
unsubscribeMouseMove = renderer.listen('document', 'mousemove', (event) => {
observer.next({
clientX: event.clientX,
clientY: event.clientY,
event,
});
});
if (IS_TOUCH_DEVICE) {
unsubscribeTouchMove = renderer.listen('document', 'touchmove', (event) => {
observer.next({
clientX: event.targetTouches[0].clientX,
clientY: event.targetTouches[0].clientY,
event,
});
});
}
});
return () => {
unsubscribeMouseMove();
if (IS_TOUCH_DEVICE) {
unsubscribeTouchMove();
}
};
}).pipe(share());
this.pointerUp = new Observable((observer) => {
let unsubscribeMouseUp;
let unsubscribeTouchEnd;
let unsubscribeTouchCancel;
zone.runOutsideAngular(() => {
unsubscribeMouseUp = renderer.listen('document', 'mouseup', (event) => {
observer.next({
clientX: event.clientX,
clientY: event.clientY,
event,
});
});
if (IS_TOUCH_DEVICE) {
unsubscribeTouchEnd = renderer.listen('document', 'touchend', (event) => {
observer.next({
clientX: event.changedTouches[0].clientX,
clientY: event.changedTouches[0].clientY,
event,
});
});
unsubscribeTouchCancel = renderer.listen('document', 'touchcancel', (event) => {
observer.next({
clientX: event.changedTouches[0].clientX,
clientY: event.changedTouches[0].clientY,
event,
});
});
}
});
return () => {
unsubscribeMouseUp();
if (IS_TOUCH_DEVICE) {
unsubscribeTouchEnd();
unsubscribeTouchCancel();
}
};
}).pipe(share());
}
static getInstance(renderer, zone) {
if (!PointerEventListeners.instance) {
PointerEventListeners.instance = new PointerEventListeners(renderer, zone);
}
return PointerEventListeners.instance;
}
}
/**
* An element placed inside a `mwlResizable` directive to be used as a drag and resize handle
*
* For example
*
* ```html
* <div mwlResizable>
* <div mwlResizeHandle [resizeEdges]="{bottom: true, right: true}"></div>
* </div>
* ```
* Or in case they are sibling elements:
* ```html
* <div mwlResizable #resizableElement="mwlResizable"></div>
* <div mwlResizeHandle [resizableContainer]="resizableElement" [resizeEdges]="{bottom: true, right: true}"></div>
* ```
*/
class ResizeHandleDirective {
constructor(renderer, element, zone, resizableDirective) {
this.renderer = renderer;
this.element = element;
this.zone = zone;
this.resizableDirective = resizableDirective;
/**
* The `Edges` object that contains the edges of the parent element that dragging the handle will trigger a resize on
*/
this.resizeEdges = {};
this.eventListeners = {};
this.destroy$ = new Subject();
}
ngOnInit() {
this.zone.runOutsideAngular(() => {
this.listenOnTheHost('mousedown').subscribe((event) => {
this.onMousedown(event, event.clientX, event.clientY);
});
this.listenOnTheHost('mouseup').subscribe((event) => {
this.onMouseup(event.clientX, event.clientY);
});
if (IS_TOUCH_DEVICE) {
this.listenOnTheHost('touchstart').subscribe((event) => {
this.onMousedown(event, event.touches[0].clientX, event.touches[0].clientY);
});
merge(this.listenOnTheHost('touchend'), this.listenOnTheHost('touchcancel')).subscribe((event) => {
this.onMouseup(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
});
}
});
}
ngOnDestroy() {
this.destroy$.next();
this.unsubscribeEventListeners();
}
/**
* @hidden
*/
onMousedown(event, clientX, clientY) {
if (event.cancelable) {
event.preventDefault();
}
if (!this.eventListeners.touchmove) {
this.eventListeners.touchmove = this.renderer.listen(this.element.nativeElement, 'touchmove', (touchMoveEvent) => {
this.onMousemove(touchMoveEvent, touchMoveEvent.targetTouches[0].clientX, touchMoveEvent.targetTouches[0].clientY);
});
}
if (!this.eventListeners.mousemove) {
this.eventListeners.mousemove = this.renderer.listen(this.element.nativeElement, 'mousemove', (mouseMoveEvent) => {
this.onMousemove(mouseMoveEvent, mouseMoveEvent.clientX, mouseMoveEvent.clientY);
});
}
this.resizable.mousedown.next({
clientX,
clientY,
edges: this.resizeEdges,
});
}
/**
* @hidden
*/
onMouseup(clientX, clientY) {
this.unsubscribeEventListeners();
this.resizable.mouseup.next({
clientX,
clientY,
edges: this.resizeEdges,
});
}
// directive might be passed from DI or as an input
get resizable() {
return this.resizableDirective || this.resizableContainer;
}
onMousemove(event, clientX, clientY) {
this.resizable.mousemove.next({
clientX,
clientY,
edges: this.resizeEdges,
event,
});
}
unsubscribeEventListeners() {
Object.keys(this.eventListeners).forEach((type) => {
this.eventListeners[type]();
delete this.eventListeners[type];
});
}
listenOnTheHost(eventName) {
return fromEvent(this.element.nativeElement, eventName).pipe(takeUntil(this.destroy$));
}
}
ResizeHandleDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizeHandleDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: ResizableDirective, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
ResizeHandleDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.3", type: ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: { resizeEdges: "resizeEdges", resizableContainer: "resizableContainer" }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizeHandleDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlResizeHandle]',
}]
}], ctorParameters: function () {
return [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: ResizableDirective, decorators: [{
type: Optional
}] }];
}, propDecorators: { resizeEdges: [{
type: Input
}], resizableContainer: [{
type: Input
}] } });
class ResizableModule {
}
ResizableModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
ResizableModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.3", ngImport: i0, type: ResizableModule, declarations: [ResizableDirective, ResizeHandleDirective], exports: [ResizableDirective, ResizeHandleDirective] });
ResizableModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableModule });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: ResizableModule, decorators: [{
type: NgModule,
args: [{
declarations: [ResizableDirective, ResizeHandleDirective],
exports: [ResizableDirective, ResizeHandleDirective],
}]
}] });
/*
* Public API Surface of angular-resizable-element
*/
/**
* Generated bundle index. Do not edit.
*/
export { ResizableDirective, ResizableModule, ResizeHandleDirective };
//# sourceMappingURL=angular-resizable-element.mjs.map
//# sourceMappingURL=angular-resizable-element.mjs.map