Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme:modal): support drag #1607

Merged
merged 3 commits into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/theme/src/services/modal/demo/drag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title:
zh-CN: 拖动
en-US: Drag
order: 1
---

## zh-CN

支持拖动对话框。

## en-US

Support for dragging dialogs.

```ts
import { Component } from '@angular/core';
import { ModalHelper } from '@delon/theme';
import { DemoModalComponent } from '@shared';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
selector: 'app-demo',
template: `
<button nz-button (click)="open()">Open</button>
`,
})
export class DemoComponent {
constructor(private modalHelper: ModalHelper, private msg: NzMessageService) {}

open(): void {
this.modalHelper.create(DemoModalComponent, { record: { a: 1, b: '2', c: new Date() } }, { drag: true }).subscribe(res => {
this.msg.info(res);
});
}
}
```
1 change: 1 addition & 0 deletions packages/theme/src/services/modal/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ Your body content
| `size` | Specify modal size | `sm,md,lg,xl,number` | `lg` |
| `exact` | Exact match return value, default is `true`, If the return value is not null (`null` or `undefined`) is considered successful, otherwise it is considered error. | `boolean` | `true` |
| `includeTabs` | Whether to wrap the tab page | `boolean` | `false` |
| `drag` | Drag | `boolean, ModalHelperDragOptions` | - |
| `modalOptions` | nz-modal raw parameters [ModalOptions](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/modal/modal-types.ts) | `ModalOptions` | - |
1 change: 1 addition & 0 deletions packages/theme/src/services/modal/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ Your body content
| `size` | 指定对话框大小 | `sm,md,lg,xl,number` | `lg` |
| `exact` | 是否精准(默认:`true`),若返回值非空值(`null`或`undefined`)视为成功,否则视为错误 | `boolean` | `true` |
| `includeTabs` | 是否包裹标签页 | `boolean` | `false` |
| `drag` | 支持拖动 | `boolean, ModalHelperDragOptions` | - |
| `modalOptions` | 对话框 [ModalOptions](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/modal/modal-types.ts) 参数 | `ModalOptions` | - |
63 changes: 57 additions & 6 deletions packages/theme/src/services/modal/modal.helper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Injectable, TemplateRef, Type } from '@angular/core';
import { Observable, Observer } from 'rxjs';
import { DragDrop, DragRef } from '@angular/cdk/drag-drop';
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, TemplateRef, Type } from '@angular/core';
import { Observable, Observer, filter, take } from 'rxjs';

import { deepMerge } from '@delon/util/other';
import type { NzSafeAny } from 'ng-zorro-antd/core/types';
Expand All @@ -14,14 +16,45 @@ export interface ModalHelperOptions {
exact?: boolean;
/** 是否包裹标签页,修复模态包含标签间距问题 */
includeTabs?: boolean;
/**
* 是否支持拖动,默认是通过标题来触发
*/
drag?: ModalHelperDragOptions | boolean;
}

export interface ModalHelperDragOptions {
/**
* 指定拖地区域的类名,若指定为 `null` 时表示整个对话框,默认:`.modal-header, .ant-modal-title`
*/
handleCls?: string | null;
}

/**
* 对话框辅助类
*/
@Injectable({ providedIn: 'root' })
export class ModalHelper {
constructor(private srv: NzModalService) {}
private document: Document;
private dragClsPrefix = 'MODAL-DRAG';

constructor(private srv: NzModalService, private drag: DragDrop, @Inject(DOCUMENT) doc: NzSafeAny) {
this.document = doc;
}

private createDragRef(options: ModalHelperDragOptions, wrapCls: string): DragRef {
const wrapEl = this.document.querySelector(wrapCls) as HTMLDivElement;
const modalEl = wrapEl.firstChild as HTMLDivElement;
const handelEl = options.handleCls ? wrapEl.querySelector<HTMLDivElement>(options.handleCls) : null;
if (handelEl) {
handelEl.classList.add(`${this.dragClsPrefix}-HANDLE`);
}

return this.drag
.createDrag(handelEl ?? modalEl)
.withHandles([handelEl ?? modalEl])
.withBoundaryElement(wrapEl)
.withRootElement(modalEl);
}

/**
* 构建一个对话框
Expand Down Expand Up @@ -53,7 +86,7 @@ export class ModalHelper {
options
);
return new Observable((observer: Observer<NzSafeAny>) => {
const { size, includeTabs, modalOptions } = options as ModalHelperOptions;
const { size, includeTabs, modalOptions, drag } = options as ModalHelperOptions;
let cls = '';
let width = '';
if (size) {
Expand All @@ -70,6 +103,16 @@ export class ModalHelper {
cls += ` ${modalOptions.nzWrapClassName}`;
delete modalOptions.nzWrapClassName;
}
let dragOptions: ModalHelperDragOptions | null;
let dragWrapCls = `${this.dragClsPrefix}-${+new Date()}`;
let dragRef: DragRef | null;
if (drag != null && drag !== false) {
dragOptions = {
handleCls: `.modal-header, .ant-modal-title`,
...(typeof drag === 'object' ? drag : {})
};
cls += ` ${this.dragClsPrefix} ${dragWrapCls}`;
}
const defaultOptions: ModalOptions = {
nzWrapClassName: cls,
nzContent: comp,
Expand All @@ -78,7 +121,15 @@ export class ModalHelper {
nzComponentParams: params
};
const subject = this.srv.create({ ...defaultOptions, ...modalOptions });
const afterClose$ = subject.afterClose.subscribe((res: NzSafeAny) => {
subject.afterOpen
.pipe(
take(1),
filter(() => dragOptions != null)
)
.subscribe(() => {
dragRef = this.createDragRef(dragOptions!!, `.${dragWrapCls}`);
});
subject.afterClose.pipe(take(1)).subscribe((res: NzSafeAny) => {
if (options!.exact === true) {
if (res != null) {
observer.next(res);
Expand All @@ -87,7 +138,7 @@ export class ModalHelper {
observer.next(res);
}
observer.complete();
afterClose$.unsubscribe();
dragRef?.dispose();
});
});
}
Expand Down
27 changes: 26 additions & 1 deletion packages/theme/src/services/modal/modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,31 @@ describe('theme: ModalHelper', () => {
fixture.detectChanges();
}));
});
describe('#drag', () => {
it('should be working', fakeAsync(() => {
modal
.create(TestModalComponent, { ret: 'true' }, { drag: true, modalOptions: { nzTitle: 'test' } })
.subscribe();
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
expect(document.querySelectorAll('.MODAL-DRAG').length).toBe(1);
}));
it('#handleCls', fakeAsync(() => {
modal
.create(
TestModalComponent,
{ ret: 'true' },
{ drag: { handleCls: '.handle' }, modalOptions: { nzTitle: 'test' } }
)
.subscribe();
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
const handle = document.querySelector<HTMLDivElement>('.MODAL-DRAG-HANDLE');
expect(handle?.classList).toContain('handle');
}));
});
});

describe('#createStatic', () => {
Expand Down Expand Up @@ -113,7 +138,7 @@ describe('theme: ModalHelper', () => {
});

@Component({
template: ` <div id="modal{{ id }}">modal{{ id }}</div> `
template: ` <div id="modal{{ id }}" class="handle">modal{{ id }}</div> `
})
class TestModalComponent {
id = '';
Expand Down
4 changes: 4 additions & 0 deletions packages/theme/system/antd/_modal.less
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,7 @@
}
}
}

.MODAL-DRAG-HANDLE {
cursor: move;
}
2 changes: 1 addition & 1 deletion scripts/site/route-paths.txt
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,4 @@
/util/pipes-format/en
/util/pipes-format/zh
/util/token/en
/util/token/zh
/util/token/zh