Skip to content

Commit

Permalink
feat(theme:modal): support build-in and focus button (#1828)
Browse files Browse the repository at this point in the history
  • Loading branch information
cipchk authored Sep 17, 2024
1 parent 89278a3 commit 145de7d
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 15 deletions.
2 changes: 2 additions & 0 deletions packages/theme/src/services/modal/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ type: Service
Based on the `NzModalService` package, it solves some known issues:

- More friendly handling callbacks
- Default Button Focus
- Responsive Width

## Usage

Expand Down
2 changes: 2 additions & 0 deletions packages/theme/src/services/modal/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ type: Service
基于 `NzModalService` 封装,它解决一些已知问题:

- 更友好的处理回调
- 按钮默认焦点
- 响应式宽度

## 用法

Expand Down
51 changes: 39 additions & 12 deletions packages/theme/src/services/modal/modal.helper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { DragDrop, DragRef } from '@angular/cdk/drag-drop';
import { DOCUMENT } from '@angular/common';
import { Injectable, TemplateRef, Type, inject } from '@angular/core';
import { Observable, Observer, filter, take } from 'rxjs';
import { Observable, Observer, delay, filter, take, tap } from 'rxjs';

import { deepMerge } from '@delon/util/other';
import type { NzSafeAny } from 'ng-zorro-antd/core/types';
import { ModalOptions, NzModalService } from 'ng-zorro-antd/modal';
import { ModalOptions, NzModalRef, NzModalService } from 'ng-zorro-antd/modal';

const CLS_DRAG = 'MODAL-DRAG';

Expand All @@ -26,6 +26,11 @@ export interface ModalHelperOptions {
* 是否强制使用 `nzData` 传递参数,若为 `false` 表示参数会直接映射到组件实例中,其他值只能通过 `NZ_MODAL_DATA` 的方式来获取参数,默认:`false`
*/
useNzData?: boolean;

/**
* 设置焦点按钮
*/
focus?: 'ok' | 'cancel';
}

export interface ModalHelperDragOptions {
Expand Down Expand Up @@ -76,20 +81,21 @@ export class ModalHelper {
* this.nzModalRef.destroy();
*/
create(
comp: TemplateRef<NzSafeAny> | Type<NzSafeAny>,
params?: NzSafeAny,
comp?: TemplateRef<NzSafeAny> | Type<NzSafeAny> | 'confirm' | 'info' | 'success' | 'error' | 'warning',
params?: NzSafeAny | ModalHelperOptions | null,
options?: ModalHelperOptions
): Observable<NzSafeAny> {
const isBuildIn = typeof comp === 'string';
options = deepMerge(
{
size: 'lg',
exact: true,
includeTabs: false
},
options
isBuildIn && arguments.length === 2 ? params : options
);
return new Observable((observer: Observer<NzSafeAny>) => {
const { size, includeTabs, modalOptions, drag, useNzData } = options as ModalHelperOptions;
const { size, includeTabs, modalOptions, drag, useNzData, focus } = options as ModalHelperOptions;
let cls: string[] = [];
let width = '';
if (size) {
Expand Down Expand Up @@ -118,25 +124,46 @@ export class ModalHelper {
};
cls.push(CLS_DRAG, dragWrapCls);
}
const subject = this.srv.create({
const mth = isBuildIn ? this.srv[comp] : this.srv.create;
const subject: NzModalRef<NzSafeAny, NzSafeAny> = mth.call(this.srv, {
nzWrapClassName: cls.join(' '),
nzContent: comp,
nzContent: isBuildIn ? undefined : comp,
nzWidth: width ? width : undefined,
nzFooter: null,
nzData: params,
...modalOptions
});
} as ModalOptions);
// 保留 nzComponentParams 原有风格,但依然可以通过 @Inject(NZ_MODAL_DATA) 获取
if (useNzData !== true) {
if (subject.componentInstance != null && useNzData !== true) {
Object.assign(subject.componentInstance, params);
}
subject.afterOpen
.pipe(
take(1),
filter(() => dragOptions != null)
tap(() => {
if (dragOptions != null) {
dragRef = this.createDragRef(dragOptions, `.${dragWrapCls}`);
}
}),
filter(() => focus != null),
delay(modalOptions?.nzNoAnimation ? 10 : 241)
)
.subscribe(() => {
dragRef = this.createDragRef(dragOptions!!, `.${dragWrapCls}`);
const btns = subject
.getElement()
.querySelector<HTMLDivElement>('.ant-modal-confirm-btns, .modal-footer')
?.querySelectorAll<HTMLButtonElement>('.ant-btn');
const btnSize = btns?.length ?? 0;
let el: HTMLButtonElement | null = null;
if (btnSize === 1) {
el = btns![0];
} else if (btnSize > 1) {
el = btns![focus === 'ok' ? 1 : 0];
}
if (el != null) {
el.focus();
el.dataset.focused = focus;
}
});
subject.afterClose.pipe(take(1)).subscribe((res: NzSafeAny) => {
if (options!.exact === true) {
Expand Down
33 changes: 30 additions & 3 deletions packages/theme/src/services/modal/modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { NZ_MODAL_DATA, NzModalModule, NzModalRef } from 'ng-zorro-antd/modal';

import { AlainThemeModule } from '../../theme.module';
import { ModalHelper } from './modal.helper';
import { ModalHelper, ModalHelperOptions } from './modal.helper';

describe('theme: ModalHelper', () => {
let modal: ModalHelper;
Expand All @@ -25,8 +25,7 @@ describe('theme: ModalHelper', () => {
});

afterEach(() => {
const a = document.querySelector('nz-modal');
if (a) a.remove();
document.querySelector('nz-modal')?.remove();
});

describe('#create', () => {
Expand Down Expand Up @@ -106,6 +105,34 @@ describe('theme: ModalHelper', () => {
expect(handle?.classList).toContain('handle');
}));
});
describe('#focus', () => {
it('should be focus ok button', fakeAsync(() => {
modal.create('confirm', {}, { focus: 'ok', modalOptions: { nzNoAnimation: true } }).subscribe();
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
const btn = document.querySelector<HTMLButtonElement>('[data-focused="ok"]');
expect(btn != null).toBe(true);
expect(btn?.classList).toContain('ant-btn-primary');
}));
it('should be focus cancel button', fakeAsync(() => {
modal.create('confirm', {}, { focus: 'cancel', modalOptions: { nzNoAnimation: true } }).subscribe();
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
const btn = document.querySelector<HTMLButtonElement>('[data-focused="cancel"]');
expect(btn != null).toBe(true);
expect(btn?.classList).not.toContain('ant-btn-primary');
}));
});
it('should argument length is 2', fakeAsync(() => {
modal.create('info', { size: '23%' } as ModalHelperOptions).subscribe();
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
const width = document.querySelector<HTMLElement>('.ant-modal')?.style.width;
expect(width).toBe('23%');
}));
});

describe('#createStatic', () => {
Expand Down

0 comments on commit 145de7d

Please sign in to comment.