diff --git a/projects/dev-app/src/app/desktop/desktop.component.ts b/projects/dev-app/src/app/desktop/desktop.component.ts index 39681d7..89e415c 100644 --- a/projects/dev-app/src/app/desktop/desktop.component.ts +++ b/projects/dev-app/src/app/desktop/desktop.component.ts @@ -1,4 +1,4 @@ -import { RndDialog } from '@acrodata/rnd-dialog'; +import { RndDialog, RndDialogDragConstraints } from '@acrodata/rnd-dialog'; import { DialogConfig, DialogRef } from '@angular/cdk/dialog'; import { ComponentType } from '@angular/cdk/portal'; import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core'; @@ -11,7 +11,7 @@ export interface AppItem { component: ComponentType; name: string; color: string; - config: DialogConfig; + config: DialogConfig & RndDialogDragConstraints; active?: boolean; } @@ -31,8 +31,8 @@ export class DesktopComponent implements OnInit { dialogConfig: DialogConfig = { data: 'Hello, World!', - width: '400px', - height: '400px', + width: '515px', + height: '530px', minWidth: '20%', minHeight: '20%', maxWidth: '80vw', @@ -90,10 +90,17 @@ export class DesktopComponent implements OnInit { openDialog(app: AppItem) { if (app.active) return; - const dialog = this.rndDialog.open(app.component, { ...this.dialogConfig, - data: app, + data: { + ...app, + dragConstraints: { + top: app.config.top, + left: app.config.left, + right: app.config.right, + bottom: app.config.bottom, + }, + }, }); dialog.closed.subscribe(v => { app.active = false; diff --git a/projects/dev-app/src/app/settings/settings.component.ts b/projects/dev-app/src/app/settings/settings.component.ts index 1335762..3196839 100644 --- a/projects/dev-app/src/app/settings/settings.component.ts +++ b/projects/dev-app/src/app/settings/settings.component.ts @@ -61,6 +61,23 @@ export class SettingsComponent { name: 'disableClose', type: 'switch', }, + top: { + name: 'top Constraint', + type: 'switch', + default: true, + }, + left: { + name: 'Left Constraint', + type: 'switch', + }, + right: { + name: 'Right Constraint', + type: 'switch', + }, + bottom: { + name: 'Bottom Constraint', + type: 'switch', + }, }; model = this.data.config; diff --git a/projects/rnd-dialog/src/lib/rnd-dialog-container.ts b/projects/rnd-dialog/src/lib/rnd-dialog-container.ts index 03414ba..89e4a5b 100644 --- a/projects/rnd-dialog/src/lib/rnd-dialog-container.ts +++ b/projects/rnd-dialog/src/lib/rnd-dialog-container.ts @@ -4,12 +4,14 @@ import { DOCUMENT } from '@angular/common'; import { AfterViewInit, ChangeDetectionStrategy, + ChangeDetectorRef, Component, inject, OnInit, ViewEncapsulation, } from '@angular/core'; import { getElementSize } from './utils'; +import { RndDialogDragConstraints } from './rnd-dialog'; type resizableHandleDir = 'n' | 'e' | 's' | 'w' | 'ne' | 'se' | 'sw' | 'nw'; @@ -20,7 +22,7 @@ type resizableHandleDir = 'n' | 'e' | 's' | 'w' | 'ne' | 'se' | 'sw' | 'nw'; templateUrl: './rnd-dialog-container.html', styleUrl: './rnd-dialog-container.scss', encapsulation: ViewEncapsulation.None, - changeDetection: ChangeDetectionStrategy.Default, + changeDetection: ChangeDetectionStrategy.OnPush, host: { 'class': 'rnd-dialog-container', 'tabindex': '-1', @@ -42,6 +44,7 @@ export class RndDialogContainer extends CdkDialogContainer implements OnInit, Af private dialog = inject(Dialog); private dialogRef = inject(DialogRef); private document = inject(DOCUMENT); + private cdr = inject(ChangeDetectorRef); get containerElement() { return this._elementRef.nativeElement as HTMLElement; @@ -50,6 +53,12 @@ export class RndDialogContainer extends CdkDialogContainer implements OnInit, Af get overlayElement() { return this.dialogRef.overlayRef.overlayElement; } + dragConstraints: RndDialogDragConstraints = { + top: false, + right: false, + bottom: false, + left: false, + }; isActive = true; @@ -86,6 +95,11 @@ export class RndDialogContainer extends CdkDialogContainer implements OnInit, Af ngOnInit(): void { const { minWidth, minHeight, maxWidth, maxHeight } = this.overlayElement.style; + const config = this._config as any; + if (config?.data?.dragConstraints) { + this.dragConstraints = { ...this.dragConstraints, ...config.data.dragConstraints }; + } + const minSize = getElementSize(minWidth, minHeight); this.minW = minSize.w || 200; this.minH = minSize.h || 200; @@ -209,6 +223,7 @@ export class RndDialogContainer extends CdkDialogContainer implements OnInit, Af this.y = nY; break; } + this.markForCheck(); }; onResizeEnd = (e: PointerEvent) => { @@ -237,6 +252,7 @@ export class RndDialogContainer extends CdkDialogContainer implements OnInit, Af (ref.containerInstance as RndDialogContainer).isActive = false; }); this.isActive = true; + this.markForCheck(); }); } @@ -247,4 +263,8 @@ export class RndDialogContainer extends CdkDialogContainer implements OnInit, Af (a, b) => +a.overlayRef.hostElement.style.zIndex - +b.overlayRef.hostElement.style.zIndex ); } + + markForCheck() { + this.cdr.markForCheck(); + } } diff --git a/projects/rnd-dialog/src/lib/rnd-dialog-drag-handle.ts b/projects/rnd-dialog/src/lib/rnd-dialog-drag-handle.ts index bbaca7f..d36d861 100644 --- a/projects/rnd-dialog/src/lib/rnd-dialog-drag-handle.ts +++ b/projects/rnd-dialog/src/lib/rnd-dialog-drag-handle.ts @@ -54,9 +54,34 @@ export class RndDialogDragHandle { const distX = e.clientX - this.pointerStartX; const distY = e.clientY - this.pointerStartY; - this.containerInstance.x = this.x + distX; - // Dragging upward cannot exceed the top of the screen, following Mac window behavior - this.containerInstance.y = Math.max(0, this.y + distY); + const container = this.containerInstance; + const constraints = container.dragConstraints; + + // Calculate new position + let newX = this.x + distX; + let newY = this.y + distY; + + // Apply drag constraints + if (constraints.left) { + newX = Math.max(0, newX); + } + if (constraints.right) { + newX = Math.min(window.innerWidth - container.w, newX); + } + if (constraints.top) { + newY = Math.max(0, newY); + } + if (constraints.bottom) { + newY = Math.min(window.innerHeight - container.h, newY); + } + + // Update the container position + container.x = newX; + container.y = newY; + + // Update DOM position + container.containerElement.style.left = `${newX}px`; + container.containerElement.style.top = `${newY}px`; }; onDragEnd = (e: PointerEvent) => { diff --git a/projects/rnd-dialog/src/lib/rnd-dialog.ts b/projects/rnd-dialog/src/lib/rnd-dialog.ts index 1634e44..f7754d7 100644 --- a/projects/rnd-dialog/src/lib/rnd-dialog.ts +++ b/projects/rnd-dialog/src/lib/rnd-dialog.ts @@ -4,6 +4,17 @@ import { ComponentType } from '@angular/cdk/portal'; import { inject, Injectable, TemplateRef } from '@angular/core'; import { RndDialogContainer } from './rnd-dialog-container'; +export interface RndDialogDragConstraints { + /** Restrict drag up */ + top?: boolean; + /** Restrict drag right */ + right?: boolean; + /** Restrict drag down */ + bottom?: boolean; + /** Restrict drag left */ + left?: boolean; +} + @Injectable({ providedIn: 'root' }) export class RndDialog { private dialog = inject(Dialog);