diff --git a/docs/zh-CN/components/form/nestedselect.md b/docs/zh-CN/components/form/nestedselect.md index a6d6f34ac..9e93c2039 100755 --- a/docs/zh-CN/components/form/nestedselect.md +++ b/docs/zh-CN/components/form/nestedselect.md @@ -686,29 +686,92 @@ 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) 中的配置以外,还支持下面一些配置 -| 属性名 | 类型 | 默认值 | 说明 | -| ----------------- | ----------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------- | -| options | `Array`或`Array` | | [选项组](./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) | -| delimiter | `boolean` | `false` | [拼接符](./options#%E6%8B%BC%E6%8E%A5%E7%AC%A6-delimiter) | -| labelField | `boolean` | `"label"` | [选项标签字段](./options#%E9%80%89%E9%A1%B9%E6%A0%87%E7%AD%BE%E5%AD%97%E6%AE%B5-labelfield) | -| valueField | `boolean` | `"value"` | [选项值字段](./options#%E9%80%89%E9%A1%B9%E5%80%BC%E5%AD%97%E6%AE%B5-valuefield) | -| joinValues | `boolean` | `true` | [拼接值](./options#%E6%8B%BC%E6%8E%A5%E5%80%BC-joinvalues) | -| extractValue | `boolean` | `false` | [提取值](./options#%E6%8F%90%E5%8F%96%E5%A4%9A%E9%80%89%E5%80%BC-extractvalue) | -| autoFill | `object` | | [自动填充](./options#%E8%87%AA%E5%8A%A8%E5%A1%AB%E5%85%85-autofill) | -| cascade | `boolean` | `false` | 设置 `true`时,当选中父节点时不自动选择子节点。 | -| withChildren | `boolean` | `false` | 设置 `true`时,选中父节点时,值里面将包含子节点的值,否则只会保留父节点的值。 | -| onlyChildren | `boolean` | `false` | 多选时,选中父节点时,是否只将其子节点加入到值中。 | -| searchable | `boolean` | `false` | 可否搜索 | -| searchPromptText | `string` | `"输入内容进行检索"` | 搜索框占位文本 | -| noResultsText | `string` | `"未找到任何结果"` | 无结果时的文本 | -| multiple | `boolean` | `false` | 可否多选 | -| hideNodePathLabel | `boolean` | `false` | 是否隐藏选择框中已选择节点的路径 label 信息 | -| onlyLeaf | `boolean` | `false` | 只允许选择叶子节点 | +| 属性名 | 类型 | 默认值 | 说明 | 版本 | +| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --- | +| options | `Array`或`Array` | | [选项组](./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) | +| delimiter | `boolean` | `false` | [拼接符](./options#%E6%8B%BC%E6%8E%A5%E7%AC%A6-delimiter) | +| labelField | `boolean` | `"label"` | [选项标签字段](./options#%E9%80%89%E9%A1%B9%E6%A0%87%E7%AD%BE%E5%AD%97%E6%AE%B5-labelfield) | +| valueField | `boolean` | `"value"` | [选项值字段](./options#%E9%80%89%E9%A1%B9%E5%80%BC%E5%AD%97%E6%AE%B5-valuefield) | +| joinValues | `boolean` | `true` | [拼接值](./options#%E6%8B%BC%E6%8E%A5%E5%80%BC-joinvalues) | +| extractValue | `boolean` | `false` | [提取值](./options#%E6%8F%90%E5%8F%96%E5%A4%9A%E9%80%89%E5%80%BC-extractvalue) | +| autoFill | `object` | | [自动填充](./options#%E8%87%AA%E5%8A%A8%E5%A1%AB%E5%85%85-autofill) | +| cascade | `boolean` | `false` | 设置 `true`时,当选中父节点时不自动选择子节点。 | +| withChildren | `boolean` | `false` | 设置 `true`时,选中父节点时,值里面将包含子节点的值,否则只会保留父节点的值。 | +| onlyChildren | `boolean` | `false` | 多选时,选中父节点时,是否只将其子节点加入到值中。 | +| searchable | `boolean` | `false` | 可否搜索 | +| searchPromptText | `string` | `"输入内容进行检索"` | 搜索框占位文本 | +| noResultsText | `string` | `"未找到任何结果"` | 无结果时的文本 | +| multiple | `boolean` | `false` | 可否多选 | +| hideNodePathLabel | `boolean` | `false` | 是否隐藏选择框中已选择节点的路径 label 信息 | +| onlyLeaf | `boolean` | `false` | 只允许选择叶子节点 | +| maxTagCount | `number` | | 标签的最大展示数量,超出数量后以收纳浮层的方式展示,仅在多选模式开启后生效 | `3.3.0` | +| overflowTagPopover | `TooltipObject` | `{"placement": "top", "trigger": "hover", "showArrow": false, "offset": [0, -10]}` | 收纳浮层的配置属性,详细配置参考[Tooltip](../tooltip#属性表) | `3.3.0` | ## 事件表 diff --git a/packages/amis/__tests__/renderers/Form/__snapshots__/nestedSelect.test.tsx.snap b/packages/amis/__tests__/renderers/Form/__snapshots__/nestedSelect.test.tsx.snap new file mode 100644 index 000000000..752b396b0 --- /dev/null +++ b/packages/amis/__tests__/renderers/Form/__snapshots__/nestedSelect.test.tsx.snap @@ -0,0 +1,151 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Renderer:NestedSelect with maxTagLength 3 1`] = ` +
+
+ +
+ +
+
+
+
+ + + + 水果 + / + + + 苹果 + + + + + + +
+
+ + + + 水果 + / + + + 香蕉 + + + + + + +
+
+ + + + 水果 + / + + + 黑莓 + + + + + + +
+
+ + + 10 ... + +
+
+
+ + + +
+
+
+
+
+
+`; diff --git a/packages/amis/__tests__/renderers/Form/nestedSelect.test.tsx b/packages/amis/__tests__/renderers/Form/nestedSelect.test.tsx new file mode 100644 index 000000000..559e3a0aa --- /dev/null +++ b/packages/amis/__tests__/renderers/Form/nestedSelect.test.tsx @@ -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(); + }); +}); diff --git a/packages/amis/src/renderers/Form/NestedSelect.tsx b/packages/amis/src/renderers/Form/NestedSelect.tsx index a453bbe5b..d8fe111fe 100644 --- a/packages/amis/src/renderers/Form/NestedSelect.tsx +++ b/packages/amis/src/renderers/Form/NestedSelect.tsx @@ -37,6 +37,8 @@ import {FormOptionsSchema} from '../../Schema'; import {supportStatic} from './StaticHoc'; import {matchSorter} from 'match-sorter'; +import type {TooltipObject} from 'amis-ui/lib/components/TooltipWrapper'; + /** * 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; + + /** + * 标签的最大展示数量,超出数量后以收纳浮层的方式展示,仅在多选模式开启后生效 + */ + maxTagCount?: number; + + /** + * 收纳标签的Popover配置 + */ + overflowTagPopover?: object; } export interface NestedSelectProps @@ -88,6 +100,8 @@ export interface NestedSelectProps onlyChildren?: boolean; hideNodePathLabel?: boolean; useMobileUI?: boolean; + maxTagCount?: number; + overflowTagPopover?: TooltipObject; } export interface NestedSelectState { @@ -914,7 +928,9 @@ export default class NestedSelectControl extends React.Component< useMobileUI, popOverContainer, env, - loadingConfig + loadingConfig, + maxTagCount, + overflowTagPopover } = this.props; const mobileUI = useMobileUI && isMobile(); @@ -925,6 +941,8 @@ export default class NestedSelectControl extends React.Component< >