mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: inputTree/treeSelect事件&动作扩充
This commit is contained in:
parent
62611cc6ea
commit
94da4a253e
@ -835,3 +835,25 @@ true false true [{label: 'A/B/C', value: 'a/b/c'},{label: 'A
|
||||
| treeContainerClassName | `string` | | tree 最外层容器类名 |
|
||||
| enableNodePath | `boolean` | `false` | 是否开启节点路径模式 |
|
||||
| pathSeparator | `string` | `/` | 节点路径的分隔符,`enableNodePath`为`true`时生效 |
|
||||
|
||||
|
||||
## 事件表
|
||||
|
||||
| 事件名称 | 事件参数 | 说明 |
|
||||
|--------------- |------------------------ |----------------------|
|
||||
| change | value: `string` 更新后的数据 | 选中值更改 |
|
||||
| add | value: `string` 新增节点信息 | 新增选项 |
|
||||
| edit | value: `string` 编辑节点信息 | 编辑选项 |
|
||||
| delete | value: `string` 删除节点信息 | 删除选项 |
|
||||
| loadFinished | value: `json` 懒加载返回的数据 | 懒加载完成触发 |
|
||||
|
||||
|
||||
## 动作表
|
||||
|
||||
| 动作名称 | 动作配置 | 说明 |
|
||||
|----------------|-------------------------------------------------- |---------------------|
|
||||
| expand | openLevel: `number`<br />initiallyOpen为false时生效| 配置展开层级 |
|
||||
| collapse | - | 关闭树|
|
||||
| clear | - | 清除数据 |
|
||||
| reset | - | 重置数据 |
|
||||
| choose | value: `string` | 更新选中值 |
|
@ -189,3 +189,25 @@ order: 60
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ----------------- | --------- | ------- | ------------------------------------------- |
|
||||
| hideNodePathLabel | `boolean` | `false` | 是否隐藏选择框中已选择节点的路径 label 信息 |
|
||||
|
||||
|
||||
## 事件表
|
||||
|
||||
| 事件名称 | 事件参数 | 说明 |
|
||||
|--------------- |------------------------ |----------------------|
|
||||
| change | value: `string` 更新后的数据 | 选中值更改 |
|
||||
| add | value: `string` 新增节点信息 | 新增选项 |
|
||||
| edit | value: `string` 编辑节点信息 | 编辑选项 |
|
||||
| delete | value: `string` 删除节点信息 | 删除选项 |
|
||||
| loadFinished | value: `json` 懒加载返回的数据 | 懒加载完成触发 |
|
||||
| blur | - | 输入框失去焦点|
|
||||
| focus | - | 输入框获取焦点 |
|
||||
|
||||
|
||||
## 动作表
|
||||
|
||||
| 动作名称 | 动作配置 | 说明 |
|
||||
|----------------|------------------------ |---------------------|
|
||||
| clear | - | 清除数据 |
|
||||
| reset | - | 重置数据 |
|
||||
| choose | value: `string` | 更新选中值 |
|
203
examples/components/EventAction/InputTreeEvent.jsx
Normal file
203
examples/components/EventAction/InputTreeEvent.jsx
Normal file
@ -0,0 +1,203 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '树形选择框',
|
||||
regions: ['body', 'toolbar', 'header'],
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
debug: true,
|
||||
body: [
|
||||
{
|
||||
name: "input-tree-clear",
|
||||
type: "action",
|
||||
label: 'clear触发器',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'clear',
|
||||
componentId: 'input-tree-action',
|
||||
description: '点击清空内容'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "input-tree-reset",
|
||||
type: "action",
|
||||
label: 'reset触发器',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'clear',
|
||||
componentId: 'input-tree-action',
|
||||
description: '点击清空内容'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "input-tree-expand",
|
||||
type: "action",
|
||||
label: 'expand触发器(openLevel: 1)',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'expand',
|
||||
componentId: 'input-tree-action',
|
||||
description: '点击展开',
|
||||
args: {
|
||||
openLevel: 1
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "input-tree-collapse",
|
||||
type: "action",
|
||||
label: 'collapse触发器',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'collapse',
|
||||
componentId: 'input-tree-action',
|
||||
description: '点击收起'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "input-tree-choose",
|
||||
type: "action",
|
||||
label: 'choose触发器(Folder A)',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'choose',
|
||||
componentId: 'input-tree-action',
|
||||
description: '点击选中特定值',
|
||||
args: {
|
||||
value: 1
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'input-tree',
|
||||
id: 'input-tree-action',
|
||||
name: 'tree',
|
||||
label: 'Tree',
|
||||
creatable: true,
|
||||
removable: true,
|
||||
editable: true,
|
||||
initiallyOpen: false,
|
||||
unfoldedLevel: 0,
|
||||
deferApi: '/api/mock2/form/deferOptions?label=${label}&waitSeconds=2',
|
||||
options: [
|
||||
{
|
||||
label: 'Folder A',
|
||||
value: 1,
|
||||
children: [
|
||||
{
|
||||
label: 'file A(懒加载)',
|
||||
defer: true,
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: 'Folder B',
|
||||
value: 3,
|
||||
children: [
|
||||
{
|
||||
label: 'file b1',
|
||||
value: 3.1
|
||||
},
|
||||
{
|
||||
label: 'file b2',
|
||||
value: 3.2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'file C',
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
label: 'file D',
|
||||
value: 5
|
||||
}
|
||||
],
|
||||
onEvent: {
|
||||
change: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发change事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
add: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发add事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
edit: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发edit事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
delete: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发delete事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
loadFinished: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发load事件'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
198
examples/components/EventAction/treeSelectEvent.jsx
Normal file
198
examples/components/EventAction/treeSelectEvent.jsx
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: 'Folder A',
|
||||
value: 1,
|
||||
children: [
|
||||
{
|
||||
label: 'file A(懒加载)',
|
||||
defer: true,
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: 'Folder B',
|
||||
value: 3,
|
||||
children: [
|
||||
{
|
||||
label: 'file b1',
|
||||
value: 3.1
|
||||
},
|
||||
{
|
||||
label: 'file b2',
|
||||
value: 3.2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'file C',
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
label: 'file D',
|
||||
value: 5
|
||||
}
|
||||
]
|
||||
|
||||
const onEvent = {
|
||||
blur: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发blur事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
focus: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发focus事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
change: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发change事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
add: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发add事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
edit: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发edit事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
delete: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发delete事件'
|
||||
}
|
||||
]
|
||||
},
|
||||
load: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'toast',
|
||||
msgType: 'info',
|
||||
msg: '派发load事件'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '树形选择器',
|
||||
regions: ['body', 'toolbar', 'header'],
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
debug: true,
|
||||
body: [
|
||||
{
|
||||
name: "tree-select-clear",
|
||||
type: "action",
|
||||
label: 'clear触发器',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'clear',
|
||||
componentId: 'tree-select-action',
|
||||
description: '点击清空内容'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "tree-select-reset",
|
||||
type: "action",
|
||||
label: 'reset触发器',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'clear',
|
||||
componentId: 'tree-select-action',
|
||||
description: '点击清空内容'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "tree-select-choose",
|
||||
type: "action",
|
||||
label: 'choose触发器(Folder A)',
|
||||
level: 'primary',
|
||||
className: 'mr-3',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'choose',
|
||||
componentId: 'tree-select-action',
|
||||
description: '点击选中特定值',
|
||||
args: {
|
||||
value: 1
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'tree-select',
|
||||
id: 'tree-select-action',
|
||||
name: 'tree',
|
||||
label: 'Tree',
|
||||
creatable: true,
|
||||
removable: true,
|
||||
editable: true,
|
||||
deferApi: '/api/mock2/form/deferOptions?label=${label}&waitSeconds=2',
|
||||
options,
|
||||
onEvent
|
||||
},
|
||||
{
|
||||
type: 'tree-select',
|
||||
id: 'tree-select-action2',
|
||||
name: 'tree多选',
|
||||
label: 'tree多选',
|
||||
multiple: true,
|
||||
creatable: true,
|
||||
removable: true,
|
||||
editable: true,
|
||||
deferApi: '/api/mock2/form/deferOptions?label=${label}&waitSeconds=2',
|
||||
options,
|
||||
onEvent
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
@ -83,6 +83,8 @@ import ButtonEventActionSchema from './EventAction/ButtonEvent';
|
||||
import InputRatingEventSchema from './EventAction/InputRatingEvent';
|
||||
import ExcelEventSchema from './EventAction/ExcelEvent';
|
||||
import WizardEventSchema from './EventAction/WizardEvent';
|
||||
import InputTreeEventSchema from './EventAction/InputTreeEvent';
|
||||
import treeSelectEventSchema from './EventAction/treeSelectEvent';
|
||||
import WizardSchema from './Wizard';
|
||||
import ChartSchema from './Chart';
|
||||
import EChartsEditorSchema from './ECharts';
|
||||
@ -587,6 +589,16 @@ export const examples = [
|
||||
path: 'examples/event/wizard',
|
||||
component: makeSchemaRenderer(WizardEventSchema)
|
||||
},
|
||||
{
|
||||
label: '树形选择框',
|
||||
path: 'examples/event/input-tree',
|
||||
component: makeSchemaRenderer(InputTreeEventSchema)
|
||||
},
|
||||
{
|
||||
label: '树形选择器',
|
||||
path: 'examples/event/tree-select',
|
||||
component: makeSchemaRenderer(treeSelectEventSchema)
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -41,6 +41,8 @@ export interface IDropInfo {
|
||||
interface TreeSelectorProps extends ThemeProps, LocaleProps {
|
||||
highlightTxt?: string;
|
||||
|
||||
onRef: any;
|
||||
|
||||
showIcon?: boolean;
|
||||
// 是否默认都展开
|
||||
initiallyOpen?: boolean;
|
||||
@ -206,6 +208,7 @@ export class TreeSelector extends React.Component<
|
||||
|
||||
componentDidMount() {
|
||||
const {enableNodePath} = this.props;
|
||||
this.props.onRef(this)
|
||||
enableNodePath && this.expandLazyLoadNodes();
|
||||
}
|
||||
|
||||
@ -246,20 +249,23 @@ export class TreeSelector extends React.Component<
|
||||
onExpandTree?.(nodePathArr);
|
||||
}
|
||||
|
||||
syncUnFolded(props: TreeSelectorProps) {
|
||||
syncUnFolded(props: TreeSelectorProps, unfoldedLevel?: Number) {
|
||||
// 传入默认展开层级需要重新初始化unfolded
|
||||
let initFoldedLevel = typeof unfoldedLevel !== 'undefined';
|
||||
let expandLevel = initFoldedLevel ? unfoldedLevel : props.unfoldedLevel;
|
||||
// 初始化树节点的展开状态
|
||||
let unfolded = this.unfolded;
|
||||
const {foldedField, unfoldedField} = this.props;
|
||||
|
||||
eachTree(props.options, (node: Option, index, level) => {
|
||||
if (unfolded.has(node)) {
|
||||
if (unfolded.has(node) && !initFoldedLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.children && node.children.length) {
|
||||
let ret: any = true;
|
||||
|
||||
if (node.defer && node.loaded) {
|
||||
if (node.defer && node.loaded && !initFoldedLevel) {
|
||||
ret = true;
|
||||
} else if (
|
||||
unfoldedField &&
|
||||
@ -270,7 +276,7 @@ export class TreeSelector extends React.Component<
|
||||
ret = !node[foldedField];
|
||||
} else {
|
||||
ret = !!props.initiallyOpen;
|
||||
if (!ret && level <= (props.unfoldedLevel as number)) {
|
||||
if (!ret && level <= (expandLevel as number)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
@ -278,6 +284,8 @@ export class TreeSelector extends React.Component<
|
||||
}
|
||||
});
|
||||
|
||||
initFoldedLevel && this.forceUpdate();
|
||||
|
||||
return unfolded;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@ import {
|
||||
} from './Options';
|
||||
import {Spinner} from '../../components';
|
||||
import {SchemaApi} from '../../Schema';
|
||||
import {autobind, createObject} from '../../utils/helper';
|
||||
import {Action} from '../../types';
|
||||
|
||||
/**
|
||||
* Tree 下拉选择框。
|
||||
@ -98,12 +100,51 @@ export default class TreeControl extends React.Component<TreeProps> {
|
||||
enableNodePath: false,
|
||||
pathSeparator: '/'
|
||||
};
|
||||
treeRef: any
|
||||
|
||||
reload() {
|
||||
const reload = this.props.reloadOptions;
|
||||
reload && reload();
|
||||
}
|
||||
|
||||
doAction(action: Action, data: {openLevel: Number, value: any}, throwErrors: boolean) {
|
||||
const {resetValue, onChange, options} = this.props;
|
||||
if (action.actionType && ['clear', 'reset'].includes(action.actionType)) {
|
||||
onChange && onChange(resetValue ?? '');
|
||||
}
|
||||
if (action.actionType === 'expand') {
|
||||
this.treeRef.syncUnFolded(this.props, data.openLevel);
|
||||
}
|
||||
if (action.actionType === 'collapse') {
|
||||
this.treeRef.syncUnFolded(this.props, 0);
|
||||
}
|
||||
if (action.actionType === 'choose') {
|
||||
onChange && onChange(data.value || '');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@autobind
|
||||
async handleChange(value: any) {
|
||||
const {onChange, dispatchEvent, data} = this.props;
|
||||
|
||||
const rendererEvent = await dispatchEvent('change', createObject(data, {
|
||||
value
|
||||
}));
|
||||
|
||||
if (rendererEvent?.prevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
onChange && onChange(value);
|
||||
}
|
||||
|
||||
@autobind
|
||||
domRef(ref: any) {
|
||||
this.treeRef = ref;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
@ -112,7 +153,6 @@ export default class TreeControl extends React.Component<TreeProps> {
|
||||
value,
|
||||
enableNodePath,
|
||||
pathSeparator = '/',
|
||||
onChange,
|
||||
disabled,
|
||||
joinValues,
|
||||
extractValue,
|
||||
@ -162,11 +202,12 @@ export default class TreeControl extends React.Component<TreeProps> {
|
||||
{loading ? null : (
|
||||
<TreeSelector
|
||||
classPrefix={ns}
|
||||
onRef={this.domRef}
|
||||
labelField={labelField}
|
||||
valueField={valueField}
|
||||
iconField={iconField}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
onChange={this.handleChange}
|
||||
joinValues={joinValues}
|
||||
extractValue={extractValue}
|
||||
delimiter={delimiter}
|
||||
|
@ -454,10 +454,10 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
this.toDispose = [];
|
||||
}
|
||||
|
||||
async dispatchChangeEvent(eventData: any = '') {
|
||||
async dispatchOptionEvent(eventName: string, eventData: any = '') {
|
||||
const {dispatchEvent, options, data} = this.props;
|
||||
const rendererEvent = await dispatchEvent(
|
||||
'change',
|
||||
eventName,
|
||||
createObject(data, {
|
||||
value: eventData,
|
||||
options,
|
||||
@ -599,7 +599,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
value
|
||||
);
|
||||
|
||||
const isPrevented = await this.dispatchChangeEvent(newValue);
|
||||
const isPrevented = await this.dispatchOptionEvent('change', newValue);
|
||||
isPrevented || (onChange && onChange(newValue, submitOnChange, changeImmediately));
|
||||
}
|
||||
|
||||
@ -667,7 +667,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
? []
|
||||
: formItem.filteredOptions.concat();
|
||||
const newValue = this.formatValueArray(valueArray);
|
||||
const isPrevented = await this.dispatchChangeEvent(newValue);
|
||||
const isPrevented = await this.dispatchOptionEvent('change', newValue);
|
||||
isPrevented || (onChange && onChange(newValue));
|
||||
}
|
||||
|
||||
@ -767,7 +767,7 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
}
|
||||
|
||||
@autobind
|
||||
deferLoad(option: Option) {
|
||||
async deferLoad(option: Option) {
|
||||
const {deferApi, source, env, formItem, data} = this.props;
|
||||
const api = option.deferApi || deferApi || source;
|
||||
|
||||
@ -779,7 +779,9 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
formItem?.deferLoadOptions(option, api, createObject(data, option));
|
||||
const json = await formItem?.deferLoadOptions(option, api, createObject(data, option));
|
||||
// 触发事件通知,加载完成
|
||||
this.dispatchOptionEvent('loadFinished',json);
|
||||
}
|
||||
|
||||
@autobind
|
||||
@ -992,6 +994,11 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
[valueField || 'value']: result[labelField || 'label']
|
||||
};
|
||||
}
|
||||
// 触发事件通知
|
||||
const isPrevented = await this.dispatchOptionEvent('add', {...result, idx});
|
||||
if (isPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是懒加载的,只懒加载当前节点。
|
||||
if (parent?.defer) {
|
||||
@ -1095,6 +1102,12 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 触发事件通知
|
||||
const isPrevented = await this.dispatchOptionEvent('edit', result);
|
||||
if (isPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (source && editApi) {
|
||||
this.reload();
|
||||
} else {
|
||||
@ -1141,6 +1154,12 @@ export function registerOptionsControl(config: OptionsConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 触发事件通知
|
||||
const isPrevented = await this.dispatchOptionEvent('delete', ctx);
|
||||
if (isPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 通过 deleteApi 删除。
|
||||
try {
|
||||
if (!deleteApi) {
|
||||
|
@ -18,9 +18,10 @@ import {Api} from '../../types';
|
||||
import {isEffectiveApi} from '../../utils/api';
|
||||
import Spinner from '../../components/Spinner';
|
||||
import ResultBox from '../../components/ResultBox';
|
||||
import {autobind, getTreeAncestors, isMobile} from '../../utils/helper';
|
||||
import {autobind, getTreeAncestors, isMobile, createObject} from '../../utils/helper';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {normalizeOptions} from '../../components/Select';
|
||||
import {Action} from '../../types';
|
||||
|
||||
/**
|
||||
* Tree 下拉选择框。
|
||||
@ -121,6 +122,8 @@ export default class TreeSelectControl extends React.Component<
|
||||
pathSeparator: '/'
|
||||
};
|
||||
|
||||
treeRef: any
|
||||
|
||||
container: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
|
||||
input: React.RefObject<any> = React.createRef();
|
||||
@ -185,16 +188,20 @@ export default class TreeSelectControl extends React.Component<
|
||||
);
|
||||
}
|
||||
|
||||
handleFocus() {
|
||||
handleFocus(e: any) {
|
||||
const {dispatchEvent} = this.props;
|
||||
this.setState({
|
||||
isFocused: true
|
||||
});
|
||||
dispatchEvent('focus', e);
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
handleBlur(e: any) {
|
||||
const {dispatchEvent} = this.props;
|
||||
this.setState({
|
||||
isFocused: false
|
||||
});
|
||||
dispatchEvent('blur', e);
|
||||
}
|
||||
|
||||
handleKeyPress(e: React.KeyboardEvent) {
|
||||
@ -257,19 +264,19 @@ export default class TreeSelectControl extends React.Component<
|
||||
}
|
||||
|
||||
handleChange(value: any) {
|
||||
const {onChange, multiple} = this.props;
|
||||
const {multiple} = this.props;
|
||||
|
||||
if (!multiple) {
|
||||
this.close();
|
||||
}
|
||||
|
||||
multiple || !this.state.inputValue
|
||||
? onChange(value)
|
||||
? this.resultChangeEvent(value)
|
||||
: this.setState(
|
||||
{
|
||||
inputValue: ''
|
||||
},
|
||||
() => onChange(value)
|
||||
() => this.resultChangeEvent(value)
|
||||
);
|
||||
}
|
||||
|
||||
@ -410,14 +417,13 @@ export default class TreeSelectControl extends React.Component<
|
||||
extractValue,
|
||||
delimiter,
|
||||
valueField,
|
||||
onChange,
|
||||
multiple
|
||||
} = this.props;
|
||||
|
||||
let newValue: any = Array.isArray(value) ? value.concat() : [];
|
||||
|
||||
if (!multiple && !newValue.length) {
|
||||
onChange('');
|
||||
this.resultChangeEvent('');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -428,8 +434,31 @@ export default class TreeSelectControl extends React.Component<
|
||||
if (joinValues) {
|
||||
newValue = newValue.join(delimiter || ',');
|
||||
}
|
||||
this.resultChangeEvent(newValue);
|
||||
}
|
||||
|
||||
onChange(newValue);
|
||||
doAction(action: Action, data: {value: any}, throwErrors: boolean) {
|
||||
const {onChange} = this.props;
|
||||
if (action.actionType && ['clear', 'reset'].includes(action.actionType)) {
|
||||
this.clearValue();
|
||||
}
|
||||
if (action.actionType === 'choose') {
|
||||
onChange && onChange(data.value || '');
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
async resultChangeEvent(value: any) {
|
||||
const {onChange, dispatchEvent, data} = this.props;
|
||||
|
||||
const rendererEvent = await dispatchEvent('change', createObject(data, {
|
||||
value
|
||||
}));
|
||||
|
||||
if (rendererEvent?.prevented) {
|
||||
return;
|
||||
}
|
||||
onChange && onChange(value);
|
||||
}
|
||||
|
||||
@autobind
|
||||
@ -449,6 +478,11 @@ export default class TreeSelectControl extends React.Component<
|
||||
}`;
|
||||
}
|
||||
|
||||
@autobind
|
||||
domRef(ref: any) {
|
||||
this.treeRef = ref;
|
||||
}
|
||||
|
||||
renderOuter() {
|
||||
const {
|
||||
value,
|
||||
@ -506,6 +540,7 @@ export default class TreeSelectControl extends React.Component<
|
||||
return (
|
||||
<TreeSelector
|
||||
classPrefix={ns}
|
||||
onRef={this.domRef}
|
||||
onlyChildren={onlyChildren}
|
||||
labelField={labelField}
|
||||
valueField={valueField}
|
||||
|
@ -104,6 +104,9 @@ export interface Action extends Button {
|
||||
| 'clear-and-submit'
|
||||
| 'toast'
|
||||
| 'goto-step'
|
||||
| 'expand'
|
||||
| 'collapse'
|
||||
| 'choose'
|
||||
| 'step-submit';
|
||||
api?: Api;
|
||||
asyncApi?: Api;
|
||||
|
Loading…
Reference in New Issue
Block a user