Skip to content

Commit

Permalink
feat: add segmented widget
Browse files Browse the repository at this point in the history
  • Loading branch information
cipchk committed Oct 21, 2023
1 parent bd65121 commit af4cc8e
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 0 deletions.
65 changes: 65 additions & 0 deletions packages/form/widgets/segmented/demo/simple.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
title:
zh-CN: 基础样例
en-US: Basic Usage
order: 0
---

## zh-CN

最简单的用法。

## en-US

Simplest of usage.

```ts
import { Component } from '@angular/core';
import { delay, of } from 'rxjs';

import { SFSchema } from '@delon/form';
import { SFSegmentedWidgetSchema, SegmentedWidget } from '@delon/form/widgets/segmented';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzSegmentedOptions } from 'ng-zorro-antd/segmented';

@Component({
selector: 'app-demo',
template: `<sf [schema]="schema" (formSubmit)="submit($event)" />`
})
export class DemoComponent {
schema: SFSchema = {
properties: {
base: {
type: 'string',
title: 'Base',
default: 2,
enum: ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'],
ui: {
widget: SegmentedWidget.KEY,
valueChange: console.log
} as SFSegmentedWidgetSchema
},
asyncData: {
type: 'string',
title: 'Async Data',
ui: {
widget: SegmentedWidget.KEY,
asyncData: () =>
of([
{ label: 'Label1', value: 'a' },
{ label: 'Label2', value: 'b' },
{ label: 'Label3', value: 'c', disabled: true }
] as NzSegmentedOptions).pipe(delay(1000)),
valueChange: console.log
} as SFSegmentedWidgetSchema
}
}
};

constructor(private msg: NzMessageService) {}

submit(value: {}): void {
this.msg.success(JSON.stringify(value));
}
}
```
22 changes: 22 additions & 0 deletions packages/form/widgets/segmented/index.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: segmented
subtitle: Segmented
type: Non-built-in widgets
---

- When displaying multiple options and user can select a single option;
- When switching the selected option, the content of the associated area changes.

## Import module

Non-built-in modules, Should be import `SegmentedWidgetModule` in [json-schema.module.ts](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/json-schema.module.ts#L11).

## API

### ui

| Property | Description | Type | Default |
|----------|-------------|------|---------|
| `[block]` | Option to fit width to its parent\'s width | `boolean` | false | |
| `[asyncData]` | Set children optional | `() => Observable<NzSegmentedOptions>` | - | |
| `(valueChange)` | Emits when index of the currently selected option changes | `(data: { index: number; item: SFValue }) => void` | - | |
20 changes: 20 additions & 0 deletions packages/form/widgets/segmented/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { DelonFormModule, WidgetRegistry } from '@delon/form';
import { NzSegmentedModule } from 'ng-zorro-antd/segmented';

import { SegmentedWidget } from './widget';

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

@NgModule({
imports: [FormsModule, DelonFormModule, NzSegmentedModule],
declarations: [SegmentedWidget]
})
export class SegmentedWidgetModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(SegmentedWidget.KEY, SegmentedWidget);
}
}
22 changes: 22 additions & 0 deletions packages/form/widgets/segmented/index.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: segmented
subtitle: 分段控制器
type: Non-built-in widgets
---

- 用于展示多个选项并允许用户选择其中单个选项;
- 当切换选中选项时,关联区域的内容会发生变化。

## 导入模块

非内置模块,需要额外在 [json-schema.module.ts](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/json-schema.module.ts#L11) 导入 `SegmentedWidgetModule`

## API

### ui 属性

| 成员 | 说明 | 类型 | 默认值 |
|----|----|----|-----|
| `[block]` | 将宽度调整为父元素宽度的选项 | `boolean` | false | |
| `[asyncData]` | 异步数据 | `() => Observable<NzSegmentedOptions>` | - | |
| `(valueChange)` | 当前选中项目变化时触发回调 | `(data: { index: number; item: SFValue }) => void` | - | |
6 changes: 6 additions & 0 deletions packages/form/widgets/segmented/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"lib": {
"flatModuleFile": "widgets-color",
"entryFile": "index.ts"
}
}
21 changes: 21 additions & 0 deletions packages/form/widgets/segmented/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { TemplateRef } from '@angular/core';
import type { Observable } from 'rxjs';

import type { SFUISchemaItem, SFValue } from '@delon/form';
import type { NzSegmentedOption, NzSegmentedOptions } from 'ng-zorro-antd/segmented';

export interface SFSegmentedWidgetSchema extends SFUISchemaItem {
/**
* 异步数据源
*/
asyncData?: () => Observable<NzSegmentedOptions>;
/**
* Option to fit width to its parent's width
*/
block?: boolean;
labelTemplate?: TemplateRef<{ $implicit: NzSegmentedOption; index: number }> | null;
/**
* Emits when index of the currently selected option changes
*/
valueChange?: (data: { index: number; item: SFValue }) => void;
}
42 changes: 42 additions & 0 deletions packages/form/widgets/segmented/widget.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { DebugElement } from '@angular/core';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';

import { SFSchema } from '@delon/form';
import { createTestContext } from '@delon/testing';

import { SegmentedWidgetModule, SFSegmentedWidgetSchema } from './index';
import { configureSFTestSuite, SFPage, TestFormComponent } from '../../spec/base.spec';

describe('form: widget: segmented', () => {
let fixture: ComponentFixture<TestFormComponent>;
let dl: DebugElement;
let context: TestFormComponent;
let page: SFPage;

configureSFTestSuite({ imports: [SegmentedWidgetModule] });

beforeEach(() => {
({ fixture, dl, context } = createTestContext(TestFormComponent));
page = new SFPage(context.comp);
page.cleanOverlay().prop(dl, context, fixture);
});

it('should be working', fakeAsync(() => {
const valueChange = jasmine.createSpy();
const s: SFSchema = {
properties: {
a: {
type: 'string',
enum: ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'],
ui: {
widget: 'segmented',
valueChange
} as SFSegmentedWidgetSchema
}
}
};
page.newSchema(s).typeEvent('click', '.ant-segmented-item:nth-child(2) .ant-segmented-item-label');
expect(page.getValue('/a')).toBe(1);
expect(valueChange).toHaveBeenCalled();
}));
});
51 changes: 51 additions & 0 deletions packages/form/widgets/segmented/widget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Component, ViewEncapsulation } from '@angular/core';

import { ControlUIWidget, SFValue, getData } from '@delon/form';
import { NzSegmentedOptions } from 'ng-zorro-antd/segmented';

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

@Component({
selector: 'sf-segmented',
template: `<sf-item-wrap
[id]="id"
[schema]="schema"
[ui]="ui"
[showError]="showError"
[error]="error"
[showTitle]="schema.title"
>
<nz-segmented
[ngModel]="value"
(ngModelChange)="setValue($event)"
[nzDisabled]="disabled"
[nzSize]="$any(ui.size)"
[nzBlock]="ui.block ?? false"
[nzOptions]="list"
[nzLabelTemplate]="ui.labelTemplate ?? null"
(nzValueChange)="valueChange($event)"
/>
</sf-item-wrap>`,
preserveWhitespaces: false,
encapsulation: ViewEncapsulation.None
})
export class SegmentedWidget extends ControlUIWidget<SFSegmentedWidgetSchema> {
static readonly KEY = 'segmented';
private _list?: NzSegmentedOptions;
get list(): NzSegmentedOptions {
return this._list ?? [];
}

reset(value: SFValue): void {
getData(this.schema, this.ui, value).subscribe(list => {
this._list = list as NzSegmentedOptions;
this.detectChanges();
});
}

valueChange(index: number): void {
if (this.ui.valueChange) {
this.ui.valueChange({ index, item: this.list[index] as SFValue });
}
}
}
2 changes: 2 additions & 0 deletions src/app/shared/json-schema/json-schema.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ColorWidgetModule } from '@delon/form/widgets/color';
import { MentionWidgetModule } from '@delon/form/widgets/mention';
import { QrCodeWidgetModule } from '@delon/form/widgets/qr-code';
import { RateWidgetModule } from '@delon/form/widgets/rate';
import { SegmentedWidgetModule } from '@delon/form/widgets/segmented';
import { SliderWidgetModule } from '@delon/form/widgets/slider';
import { TagWidgetModule } from '@delon/form/widgets/tag';
import { TimeWidgetModule } from '@delon/form/widgets/time';
Expand Down Expand Up @@ -34,6 +35,7 @@ import { SharedModule } from '../shared.module';
UploadWidgetModule,
ColorWidgetModule,
QrCodeWidgetModule,
SegmentedWidgetModule,
MonacoEditorWidgetModule,
TinymceWidgetModule
]
Expand Down

0 comments on commit af4cc8e

Please sign in to comment.