Skip to content

Commit

Permalink
Merge 4ac35a9 into 065316a
Browse files Browse the repository at this point in the history
  • Loading branch information
cipchk authored Nov 12, 2023
2 parents 065316a + 4ac35a9 commit fa3d555
Show file tree
Hide file tree
Showing 67 changed files with 660 additions and 432 deletions.
49 changes: 29 additions & 20 deletions packages/form/docs/customize.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ Making a set of widgets for project can lead to faster development work.
A widget is a component. You only need to inherit `ControlWidget` to create a widget. For example:

```ts
import { Component, OnInit } from '@angular/core';
import { ControlWidget } from '@delon/form';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ControlWidget, DelonFormModule, SFWidgetProvideConfig } from '@delon/form';

export function withTestWidget(): SFWidgetProvideConfig {
return { KEY: 'test', type: TestWidget };
}

@Component({
selector: 'sf-tinymce',
Expand All @@ -38,11 +42,17 @@ import { ControlWidget } from '@delon/form';
[loading]="loading">
</tinymce>
<!-- End area -->
</sf-item-wrap>`
</sf-item-wrap>`,
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [DelonFormModule]
})
export class TinymceWidget extends ControlWidget implements OnInit {
static readonly KEY = 'tinymce';
class TestWidget extends ControlWidget implements OnInit {
/* KEY value for registering widgets */
static readonly KEY = 'test';

// It is recommended to use `ngOnInit` to obtain the parameters required by the component.
config: any;
loadingTip: string;

Expand All @@ -51,6 +61,7 @@ export class TinymceWidget extends ControlWidget implements OnInit {
this.config = this.ui.config || {};
}

// reset can better solve the problem of new data required during the form reset process
reset(value: string) {

}
Expand All @@ -72,34 +83,32 @@ The widget is manually trigger changed detection during the rendering process. I

### Register

Define the widget component in the root module (includes: `declarations`), import `WidgetRegistry` in the module and register the custom widget.
Recommended to define a widget called `withXWidth` and return `SFWidgetProvideConfig` type, for example:

```ts
@NgModule({
declarations: [ TinymceWidget ],
imports: [
DelonFormModule.forRoot()
]
})
export class AppModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(TinymceWidget.KEY, TinymceWidget);
}
export function withTestWidget(): SFWidgetProvideConfig {
return { KEY: 'test', type: TestWidget };
}
```

Of course, for more friendly maintenance, recommended to define a Json schema module in the Shared directory. Please refer to [ng-alain implementation](https://github.com/ng-alain/ng-alain/blob/master/ Src/app/shared/json-schema/json-schema.module.ts).
Finally, register via `provideSFConfig`:

```ts
provideSFConfig({ widgets: [ withTestWidget() ] })
```

For more friendly maintenance, recommended to define a project-specific collection in the `shared` directory. If you are interested, please refer to [NG-ALAIN implementation](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/) or refer to [@delon/form/widgets/autocomplete](https://github.com/ng-alain/delon/tree/master/packages/form/widgets/autocomplete).

### Usage

Just like other widgets, just specify the `widget` value, for example:

```json
"intro": {
"test": {
"type": "string",
"ui": {
"widget": "tinymce",
"loadingTip": "loading..."
"widget": "test",
"data": "widget parameters"
}
}
```
48 changes: 27 additions & 21 deletions packages/form/docs/customize.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ type: Documents

**自己创建小部件**

小部件就是一个组件,你只需要继承 `ControlWidget` 就相当于构建一个小部件,其结构如下
小部件就是一个组件,你只需要继承 `ControlWidget` 就相当于构建一个小部件,例如

```ts
import { Component, OnInit } from '@angular/core';
import { ControlWidget } from '@delon/form';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ControlWidget, DelonFormModule, SFWidgetProvideConfig } from '@delon/form';

export function withTestWidget(): SFWidgetProvideConfig {
return { KEY: 'test', type: TestWidget };
}

@Component({
selector: 'sf-tinymce',
Expand All @@ -38,11 +42,15 @@ import { ControlWidget } from '@delon/form';
[loading]="loading">
</tinymce>
<!-- 结束自定义控件区域 -->
</sf-item-wrap>`
</sf-item-wrap>`,
preserveWhitespaces: false,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [DelonFormModule]
})
export class TinymceWidget extends ControlWidget implements OnInit {
class TestWidget extends ControlWidget implements OnInit {
/* 用于注册小部件 KEY 值 */
static readonly KEY = 'tinymce';
static readonly KEY = 'test';

// 组件所需要的参数,建议使用 `ngOnInit` 获取
config: any;
Expand Down Expand Up @@ -75,34 +83,32 @@ export class TinymceWidget extends ControlWidget implements OnInit {

### 注册小部件

在根模块中定义(`declarations`)注册小部件组件,同时在模块中导入 `WidgetRegistry` 并注册自定义小部件。
建议在小部件内定义一个名为 `withXWidth` 并返回 `SFWidgetProvideConfig`,例如:

```ts
@NgModule({
declarations: [ TinymceWidget ],
imports: [
DelonFormModule.forRoot()
]
})
export class AppModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(TinymceWidget.KEY, TinymceWidget);
}
export function withTestWidget(): SFWidgetProvideConfig {
return { KEY: 'test', type: TestWidget };
}
```

当然为了更友好的维护,建议在Shared目录下定义一个专属 Json schema 模块,有兴趣可参考 [ng-alain实现](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/json-schema.module.ts)
最后,通过 `provideSFConfig` 来注册:

```ts
provideSFConfig({ widgets: [ withTestWidget() ] })
```

当然为了更友好的维护,建议在Shared目录下定义项目专属的集合,有兴趣可参考 [ng-alain实现](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/)或参考[@delon/form/widgets/autocomplete](https://github.com/ng-alain/delon/tree/master/packages/form/widgets/autocomplete)

### 使用自定义小部件

同其他小部件一样,只需要指定 `widget` 值,例如:

```json
"intro": {
"test": {
"type": "string",
"ui": {
"widget": "tinymce",
"loadingTip": "loading..."
"widget": "test",
"data": "widget parameters"
}
}
```
2 changes: 1 addition & 1 deletion packages/form/public_api.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './src/form';
export * from './src/index';
8 changes: 5 additions & 3 deletions packages/form/spec/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AlainThemeModule } from '@delon/theme';
import { deepCopy, deepGet } from '@delon/util/other';
import { NzSafeAny } from 'ng-zorro-antd/core/types';

import { SFWidgetProvideConfig, provideSFConfig } from '../src';
import { SF_SEQ } from '../src/const';
import { SFButton } from '../src/interface';
import { FormProperty } from '../src/model/form.property';
Expand Down Expand Up @@ -73,17 +74,18 @@ export function builder(options?: {
};
}

export function configureSFTestSuite(options?: { imports?: NzSafeAny[] }): void {
export function configureSFTestSuite(options?: { imports?: NzSafeAny[]; widgets?: SFWidgetProvideConfig[] }): void {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
NoopAnimationsModule,
AlainThemeModule,
DelonFormModule.forRoot(),
DelonFormModule,
HttpClientTestingModule,
...(options?.imports ?? [])
],
declarations: [TestFormComponent]
declarations: [TestFormComponent],
providers: [provideSFConfig({ widgets: options?.widgets })]
});
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/form/src/form.ts → packages/form/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export * from './model/index';
export * from './widget';
export * from './widgets/index';
export * from './widget.factory';
export * from './provide';

// other
export * from './validator.factory';
Expand Down
45 changes: 45 additions & 0 deletions packages/form/src/provide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
ENVIRONMENT_INITIALIZER,
EnvironmentProviders,
NgZone,
Provider,
inject,
makeEnvironmentProviders
} from '@angular/core';

import { AlainConfigService } from '@delon/util/config';
import type { NzSafeAny } from 'ng-zorro-antd/core/types';

import { AjvSchemaValidatorFactory, SchemaValidatorFactory } from './validator.factory';
import { WidgetRegistry } from './widget.factory';
import { NzWidgetRegistry } from './widgets/nz-widget.registry';

export interface SFWidgetProvideConfig {
KEY: string;
type: NzSafeAny;
}

/**
* Just only using Standalone widgets
*/
export function provideSFConfig(options?: { widgets?: SFWidgetProvideConfig[] }): EnvironmentProviders {
const provides: Array<Provider | EnvironmentProviders> = [
{
provide: SchemaValidatorFactory,
useClass: AjvSchemaValidatorFactory,
deps: [AlainConfigService, NgZone]
},
{ provide: WidgetRegistry, useClass: NzWidgetRegistry }
];
if (options?.widgets) {
provides.push({
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useValue: () => {
const srv = inject(WidgetRegistry);
options?.widgets?.forEach(widget => srv.register(widget.KEY, widget.type));
}
});
}
return makeEnvironmentProviders(provides);
}
18 changes: 4 additions & 14 deletions packages/form/widgets-third/monaco-editor/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { NuMonacoEditorModule } from '@ng-util/monaco-editor';

import { DelonFormModule, WidgetRegistry } from '@delon/form';
import { SFWidgetProvideConfig } from '@delon/form';

import { MonacoEditorWidget } from './widget';

export * from './widget';
export * from './schema';
export * from './module';

@NgModule({
imports: [FormsModule, DelonFormModule, NuMonacoEditorModule],
declarations: [MonacoEditorWidget]
})
export class MonacoEditorWidgetModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(MonacoEditorWidget.KEY, MonacoEditorWidget);
}
export function withMonacoEditorWidget(): SFWidgetProvideConfig {
return { KEY: MonacoEditorWidget.KEY, type: MonacoEditorWidget };
}
17 changes: 17 additions & 0 deletions packages/form/widgets-third/monaco-editor/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { NuMonacoEditorModule } from '@ng-util/monaco-editor';

import { DelonFormModule, WidgetRegistry } from '@delon/form';

import { MonacoEditorWidget } from './widget';

@NgModule({
imports: [FormsModule, DelonFormModule, NuMonacoEditorModule, MonacoEditorWidget]
})
export class MonacoEditorWidgetModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(MonacoEditorWidget.KEY, MonacoEditorWidget);
}
}
13 changes: 9 additions & 4 deletions packages/form/widgets-third/monaco-editor/widget.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Component } from '@angular/core';
import { Component, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';

import type { NuMonacoEditorEvent } from '@ng-util/monaco-editor';
import { NuMonacoEditorComponent, type NuMonacoEditorEvent } from '@ng-util/monaco-editor';

import { ControlUIWidget } from '@delon/form';
import { ControlUIWidget, DelonFormModule } from '@delon/form';

import type { MonacoEditorWidgetSchema } from './schema';

Expand All @@ -29,7 +30,11 @@ import type { MonacoEditorWidgetSchema } from './schema';
(event)="_event($event)"
/>
</sf-item-wrap>
`
`,
preserveWhitespaces: false,
encapsulation: ViewEncapsulation.None,
standalone: true,
imports: [FormsModule, DelonFormModule, NuMonacoEditorComponent]
})
export class MonacoEditorWidget extends ControlUIWidget<MonacoEditorWidgetSchema> {
static readonly KEY = 'monaco-editor';
Expand Down
18 changes: 4 additions & 14 deletions packages/form/widgets-third/tinymce/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { NgxTinymceModule } from 'ngx-tinymce';

import { DelonFormModule, WidgetRegistry } from '@delon/form';
import type { SFWidgetProvideConfig } from '@delon/form';

import { TinymceWidget } from './widget';

export * from './widget';
export * from './schema';
export * from './module';

@NgModule({
imports: [FormsModule, DelonFormModule, NgxTinymceModule],
declarations: [TinymceWidget]
})
export class TinymceWidgetModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(TinymceWidget.KEY, TinymceWidget);
}
export function withTinymceWidget(): SFWidgetProvideConfig {
return { KEY: TinymceWidget.KEY, type: TinymceWidget };
}
17 changes: 17 additions & 0 deletions packages/form/widgets-third/tinymce/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { NgxTinymceModule } from 'ngx-tinymce';

import { DelonFormModule, WidgetRegistry } from '@delon/form';

import { TinymceWidget } from './widget';

@NgModule({
imports: [FormsModule, DelonFormModule, NgxTinymceModule, TinymceWidget]
})
export class TinymceWidgetModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(TinymceWidget.KEY, TinymceWidget);
}
}
Loading

0 comments on commit fa3d555

Please sign in to comment.