Merge pull request #7423 from lurunze1226/feat-nested-select-overflow

feat: NestedSelect组件支持最大展示标签数量
This commit is contained in:
hsm-lv 2023-07-10 10:38:37 +08:00 committed by GitHub
commit 6d2dd47a9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 367 additions and 20 deletions

View File

@ -686,12 +686,73 @@ order: 31
} }
``` ```
## 限制标签最大展示数量
> 3.3.0 及以上版本
`maxTagCount`可以限制标签的最大展示数量,超出数量的部分会收纳到 Popover 中,可以通过`overflowTagPopover`配置 Popover 相关的[属性](../tooltip#属性表),注意该属性仅在多选模式开启后生效。
```schema: scope="body"
{
"type": "form",
"body": [
{
"type": "nested-select",
"name": "nestedSelect",
"label": "级联选择器",
"multiple": true,
"maxTagCount": 3,
"overflowTagPopover": {
"title": "已选项"
},
"value": "Apple,Banana,Blackberry,Blueberry,Cherry,Carambola,Coconut,Kiwifruit,Lemon,Pineapple,Vegetables,Wheat,Rice",
"options": [
{
"label": "水果",
"value": "Fruits",
"children" : [
{"label": "苹果", "value": "Apple"},
{"label": "香蕉", "value": "Banana"},
{"label": "黑莓", "value": "Blackberry"},
{"label": "蓝莓", "value": "Blueberry"},
{"label": "樱桃", "value": "Cherry"},
{"label": "杨桃", "value": "Carambola"},
{"label": "椰子", "value": "Coconut"},
{"label": "猕猴桃", "value": "Kiwifruit"},
{"label": "柠檬", "value": "Lemon"},
{"label": "菠萝", "value": "Pineapple"}
]
},
{
"label": "蔬菜",
"value": "Vegetables",
"children": [
{"label": "西兰花", "value": "Broccoli"},
{"label": "菠菜", "value": "Spinach"},
{"label": "南瓜", "value": "Pumpkin"}
]
},
{
"label": "谷物",
"value": "Grain",
"children": [
{"label": "小麦", "value": "Wheat"},
{"label": "水稻", "value": "Rice"},
{"label": "燕麦", "value": "Oats"}
]
}
]
}
]
}
```
## 属性表 ## 属性表
当做选择器表单项使用时,除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置 当做选择器表单项使用时,除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
| 属性名 | 类型 | 默认值 | 说明 | | 属性名 | 类型 | 默认值 | 说明 | 版本 |
| ----------------- | ----------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------- | | ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --- |
| options | `Array<object>`或`Array<string>` | | [选项组](./options#%E9%9D%99%E6%80%81%E9%80%89%E9%A1%B9%E7%BB%84-options) | | options | `Array<object>`或`Array<string>` | | [选项组](./options#%E9%9D%99%E6%80%81%E9%80%89%E9%A1%B9%E7%BB%84-options) |
| source | `string`或 [API](../../../docs/types/api) | | [动态选项组](./options#%E5%8A%A8%E6%80%81%E9%80%89%E9%A1%B9%E7%BB%84-source) | | source | `string`或 [API](../../../docs/types/api) | | [动态选项组](./options#%E5%8A%A8%E6%80%81%E9%80%89%E9%A1%B9%E7%BB%84-source) |
| delimiter | `boolean` | `false` | [拼接符](./options#%E6%8B%BC%E6%8E%A5%E7%AC%A6-delimiter) | | delimiter | `boolean` | `false` | [拼接符](./options#%E6%8B%BC%E6%8E%A5%E7%AC%A6-delimiter) |
@ -709,6 +770,8 @@ order: 31
| multiple | `boolean` | `false` | 可否多选 | | multiple | `boolean` | `false` | 可否多选 |
| hideNodePathLabel | `boolean` | `false` | 是否隐藏选择框中已选择节点的路径 label 信息 | | hideNodePathLabel | `boolean` | `false` | 是否隐藏选择框中已选择节点的路径 label 信息 |
| onlyLeaf | `boolean` | `false` | 只允许选择叶子节点 | | onlyLeaf | `boolean` | `false` | 只允许选择叶子节点 |
| maxTagCount | `number` | | 标签的最大展示数量,超出数量后以收纳浮层的方式展示,仅在多选模式开启后生效 | `3.3.0` |
| overflowTagPopover | `TooltipObject` | `{"placement": "top", "trigger": "hover", "showArrow": false, "offset": [0, -10]}` | 收纳浮层的配置属性,详细配置参考[Tooltip](../tooltip#属性表) | `3.3.0` |
## 事件表 ## 事件表

View File

@ -0,0 +1,151 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:NestedSelect with maxTagLength 3 1`] = `
<div>
<form
class="cxd-Form cxd-Form--normal"
novalidate=""
>
<input
style="display: none;"
type="submit"
/>
<div
class="cxd-Form-item cxd-Form-item--normal"
data-role="form-item"
>
<label
class="cxd-Form-label"
>
<span>
<span
class="cxd-TplField"
>
<span>
NestedSelect
</span>
</span>
</span>
</label>
<div
class="cxd-NestedSelectControl cxd-Form-control"
>
<div
class="cxd-ResultBox cxd-NestedSelect cxd-NestedSelect--multi is-clickable is-group"
tabindex="0"
>
<div
class="cxd-ResultBox-value-wrap"
>
<div
class="cxd-ResultBox-value"
>
<span
class="cxd-ResultBox-valueLabel"
>
<span
class="cxd-Select-valueLabel"
title="水果 / 苹果"
>
<span>
水果
/
</span>
<span>
苹果
</span>
</span>
</span>
<a
data-index="0"
>
<icon-mock
classname="icon icon-close"
icon="close"
/>
</a>
</div>
<div
class="cxd-ResultBox-value"
>
<span
class="cxd-ResultBox-valueLabel"
>
<span
class="cxd-Select-valueLabel"
title="水果 / 香蕉"
>
<span>
水果
/
</span>
<span>
香蕉
</span>
</span>
</span>
<a
data-index="1"
>
<icon-mock
classname="icon icon-close"
icon="close"
/>
</a>
</div>
<div
class="cxd-ResultBox-value"
>
<span
class="cxd-ResultBox-valueLabel"
>
<span
class="cxd-Select-valueLabel"
title="水果 / 黑莓"
>
<span>
水果
/
</span>
<span>
黑莓
</span>
</span>
</span>
<a
data-index="2"
>
<icon-mock
classname="icon icon-close"
icon="close"
/>
</a>
</div>
<div
class="cxd-ResultBox-value"
>
<span
class="cxd-ResultBox-valueLabel"
>
+ 10 ...
</span>
</div>
</div>
<div
class="cxd-ResultBox-actions"
>
<span
class="cxd-ResultBox-pc-arrow"
>
<icon-mock
classname="icon icon-right-arrow-bold"
icon="right-arrow-bold"
/>
</span>
</div>
</div>
</div>
</div>
</form>
</div>
`;

View File

@ -0,0 +1,115 @@
/**
* NestedSelect
*
* 01. maxTagLength
*/
import {render, cleanup, waitFor} from '@testing-library/react';
import '../../../src';
import {render as amisRender} from '../../../src';
import {makeEnv} from '../../helper';
import {clearStoresCache} from '../../../src';
afterEach(() => {
cleanup();
clearStoresCache();
});
const setupNestedSelect = async (
schema: any = {},
props: any = {},
env: any = {}
) => {
const renderResult = render(
amisRender(
{
type: 'form',
wrapWithPanel: false,
body: [
{
type: 'nested-select',
name: 'nestedSelect',
label: 'NestedSelect',
...schema
}
]
},
{...props},
makeEnv({...env})
)
);
await waitFor(() => {
expect(
renderResult.container.querySelector('.cxd-NestedSelectControl')
).toBeInTheDocument();
});
const cmpt = renderResult.container.querySelector(
'.cxd-ResultBox .cxd-NestedSelect'
) as HTMLDivElement;
return {
...renderResult,
cmpt
};
};
describe('Renderer:NestedSelect', () => {
test('with maxTagLength 3', async () => {
const {container, cmpt, queryByText} = await setupNestedSelect({
multiple: true,
maxTagCount: 3,
overflowTagPopover: {
title: '已选项'
},
value:
'Apple,Banana,Blackberry,Blueberry,Cherry,Carambola,Coconut,Kiwifruit,Lemon,Pineapple,Vegetables,Wheat,Rice',
options: [
{
label: '水果',
value: 'Fruits',
children: [
{label: '苹果', value: 'Apple'},
{label: '香蕉', value: 'Banana'},
{label: '黑莓', value: 'Blackberry'},
{label: '蓝莓', value: 'Blueberry'},
{label: '樱桃', value: 'Cherry'},
{label: '杨桃', value: 'Carambola'},
{label: '椰子', value: 'Coconut'},
{label: '猕猴桃', value: 'Kiwifruit'},
{label: '柠檬', value: 'Lemon'},
{label: '菠萝', value: 'Pineapple'}
]
},
{
label: '蔬菜',
value: 'Vegetables',
children: [
{label: '西兰花', value: 'Broccoli'},
{label: '菠菜', value: 'Spinach'},
{label: '南瓜', value: 'Pumpkin'}
]
},
{
label: '谷物',
value: 'Grain',
children: [
{label: '小麦', value: 'Wheat'},
{label: '水稻', value: 'Rice'},
{label: '燕麦', value: 'Oats'}
]
}
]
});
const list = container.querySelectorAll('.cxd-ResultBox-value-wrap')[0];
/** Tag 数量正确 */
expect(list.childNodes.length).toBe(4);
const overflowText = '+ 10 ...';
/** 收纳 Tag 可见 */
expect(queryByText(overflowText)).toBeVisible();
expect(container).toMatchSnapshot();
});
});

View File

@ -37,6 +37,8 @@ import {FormOptionsSchema} from '../../Schema';
import {supportStatic} from './StaticHoc'; import {supportStatic} from './StaticHoc';
import {matchSorter} from 'match-sorter'; import {matchSorter} from 'match-sorter';
import type {TooltipObject} from 'amis-ui/lib/components/TooltipWrapper';
/** /**
* Nested Select * Nested Select
* https://aisuda.bce.baidu.com/amis/zh-CN/components/form/nested-select * https://aisuda.bce.baidu.com/amis/zh-CN/components/form/nested-select
@ -77,6 +79,16 @@ export interface NestedSelectControlSchema extends FormOptionsSchema {
* *
*/ */
hideNodePathLabel?: boolean; hideNodePathLabel?: boolean;
/**
*
*/
maxTagCount?: number;
/**
* Popover配置
*/
overflowTagPopover?: object;
} }
export interface NestedSelectProps export interface NestedSelectProps
@ -88,6 +100,8 @@ export interface NestedSelectProps
onlyChildren?: boolean; onlyChildren?: boolean;
hideNodePathLabel?: boolean; hideNodePathLabel?: boolean;
useMobileUI?: boolean; useMobileUI?: boolean;
maxTagCount?: number;
overflowTagPopover?: TooltipObject;
} }
export interface NestedSelectState { export interface NestedSelectState {
@ -914,7 +928,9 @@ export default class NestedSelectControl extends React.Component<
useMobileUI, useMobileUI,
popOverContainer, popOverContainer,
env, env,
loadingConfig loadingConfig,
maxTagCount,
overflowTagPopover
} = this.props; } = this.props;
const mobileUI = useMobileUI && isMobile(); const mobileUI = useMobileUI && isMobile();
@ -925,6 +941,8 @@ export default class NestedSelectControl extends React.Component<
> >
<ResultBox <ResultBox
useMobileUI={useMobileUI} useMobileUI={useMobileUI}
maxTagCount={maxTagCount}
overflowTagPopover={overflowTagPopover}
disabled={disabled} disabled={disabled}
ref={this.domRef} ref={this.domRef}
placeholder={__(placeholder ?? 'placeholder.empty')} placeholder={__(placeholder ?? 'placeholder.empty')}