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 build-in and focus button #1828

Merged
merged 3 commits into from
Sep 17, 2024
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
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 @@
* 是否强制使用 `nzData` 传递参数,若为 `false` 表示参数会直接映射到组件实例中,其他值只能通过 `NZ_MODAL_DATA` 的方式来获取参数,默认:`false`
*/
useNzData?: boolean;

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

export interface ModalHelperDragOptions {
Expand Down Expand Up @@ -76,20 +81,21 @@
* 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 @@
};
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];

Check warning on line 159 in packages/theme/src/services/modal/modal.helper.ts

View check run for this annotation

Codecov / codecov/patch

packages/theme/src/services/modal/modal.helper.ts#L159

Added line #L159 was not covered by tests
} 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
Loading