-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(designable): add data source setter (#1746)
- Loading branch information
CoCoManYY
authored
Jul 9, 2021
1 parent
4ad1884
commit a6206e8
Showing
16 changed files
with
5,310 additions
and
4,616 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
designable/setters/src/DataSourceSetter/DataSettingPanel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import React, { useMemo, Fragment, useEffect } from 'react' | ||
import { Button } from 'antd' | ||
import { PlusOutlined } from '@ant-design/icons' | ||
import { ArrayItems, Form, Input, FormItem } from '@formily/antd' | ||
import { createForm } from '@formily/core' | ||
import { observer } from '@formily/reactive-react' | ||
import { createSchemaField } from '@formily/react' | ||
import { ValueInput } from '@designable/react-settings-form' | ||
import { usePrefix, TextWidget } from '@designable/react' | ||
import { Header } from './Header' | ||
import { tranverseTree } from './shared' | ||
import { ITreeDataSource } from './types' | ||
import './styles.less' | ||
|
||
const SchemaField = createSchemaField({ | ||
components: { | ||
FormItem, | ||
Input, | ||
ArrayItems, | ||
ValueInput, | ||
}, | ||
}) | ||
|
||
export interface IDataSettingPanelProps { | ||
treeDataSource: ITreeDataSource | ||
} | ||
|
||
export const DataSettingPanel: React.FC<IDataSettingPanelProps> = observer( | ||
(props) => { | ||
const prefix = usePrefix('data-source-setter') | ||
const form = useMemo(() => { | ||
let values | ||
tranverseTree(props.treeDataSource.dataSource, (dataItem, i) => { | ||
if (dataItem.key === props.treeDataSource.selectedkey) { | ||
values = dataItem | ||
} | ||
}) | ||
return createForm({ | ||
values, | ||
}) | ||
}, [props.treeDataSource.selectedkey]) | ||
if (!props.treeDataSource.selectedkey) | ||
return ( | ||
<Fragment> | ||
<Header | ||
title={ | ||
<TextWidget token="SettingComponents.DataSourceSetter.nodeProperty" /> | ||
} | ||
extra={null} | ||
/> | ||
<div className={`${prefix + '-layout-item-content'}`}> | ||
<TextWidget token="SettingComponents.DataSourceSetter.pleaseSelectNode" /> | ||
</div> | ||
</Fragment> | ||
) | ||
return ( | ||
<Fragment> | ||
<Header | ||
title={ | ||
<TextWidget token="SettingComponents.DataSourceSetter.nodeProperty" /> | ||
} | ||
extra={ | ||
<Button | ||
type="text" | ||
onClick={() => { | ||
form.setFieldState('map', (state) => { | ||
state.value.push({}) | ||
}) | ||
}} | ||
icon={<PlusOutlined />} | ||
> | ||
<TextWidget token="SettingComponents.DataSourceSetter.addKeyValuePair" /> | ||
</Button> | ||
} | ||
/> | ||
<div className={`${prefix + '-layout-item-content'}`}> | ||
<Form form={form}> | ||
<SchemaField> | ||
<SchemaField.Array name="map" x-component="ArrayItems"> | ||
<SchemaField.Object x-decorator="ArrayItems.Item"> | ||
<SchemaField.String | ||
title={ | ||
<TextWidget token="SettingComponents.DataSourceSetter.label" /> | ||
} | ||
x-decorator="FormItem" | ||
name="label" | ||
x-component="Input" | ||
/> | ||
<SchemaField.String | ||
title={ | ||
<TextWidget token="SettingComponents.DataSourceSetter.value" /> | ||
} | ||
x-decorator="FormItem" | ||
name="value" | ||
x-component="ValueInput" | ||
/> | ||
<SchemaField.Void | ||
x-component="ArrayItems.Remove" | ||
x-component-props={{ | ||
style: { | ||
margin: 5, | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
}, | ||
}} | ||
/> | ||
</SchemaField.Object> | ||
</SchemaField.Array> | ||
</SchemaField> | ||
</Form> | ||
</div> | ||
</Fragment> | ||
) | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React, { ReactNode } from 'react' | ||
import { observer } from '@formily/reactive-react' | ||
import { usePrefix } from '@designable/react' | ||
import './styles.less' | ||
|
||
export interface IHeaderProps { | ||
extra: ReactNode | null | ||
title: ReactNode | string | ||
} | ||
|
||
export const Header: React.FC<IHeaderProps> = observer(({ extra, title }) => { | ||
const prefix = usePrefix('data-source-setter') | ||
return ( | ||
<div className={`${prefix + '-layout-item-header'}`}> | ||
<div className={`${prefix + '-layout-item-title'}`}>{title}</div> | ||
{extra} | ||
</div> | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React from 'react' | ||
import { clone } from '@formily/shared' | ||
import { observer } from '@formily/reactive-react' | ||
import { IconWidget, TextWidget } from '@designable/react' | ||
import { INodeItem, ITreeDataSource } from './types' | ||
import { tranverseTree } from './shared' | ||
import './styles.less' | ||
export interface ITitleProps extends INodeItem { | ||
treeDataSource: ITreeDataSource | ||
} | ||
|
||
export const Title: React.FC<ITitleProps> = observer((props) => { | ||
const getTitleValue = (dataSource) => { | ||
const optionalKeys = ['label', 'title', 'header'] | ||
let nodeTitle | ||
optionalKeys.some((key) => { | ||
const title = (dataSource || [])?.find( | ||
(item) => item.label === key | ||
)?.value | ||
if (title !== undefined) { | ||
nodeTitle = title | ||
return true | ||
} | ||
return false | ||
}) | ||
if (nodeTitle === undefined) { | ||
;(dataSource || [])?.some((item) => { | ||
if (item.value && typeof item.value === 'string') { | ||
nodeTitle = item.value | ||
return true | ||
} | ||
return false | ||
}) | ||
} | ||
return nodeTitle | ||
} | ||
|
||
const renderTitle = (dataSource) => { | ||
const nodeTitle = getTitleValue(dataSource) | ||
if (nodeTitle === undefined) | ||
return ( | ||
<TextWidget token="SettingComponents.DataSourceSetter.defaultTitle" /> | ||
) | ||
else return nodeTitle + '' | ||
} | ||
|
||
return ( | ||
<span> | ||
<span style={{ marginRight: '5px' }}> | ||
{renderTitle(props?.map || [])} | ||
</span> | ||
<IconWidget | ||
infer="Remove" | ||
onClick={() => { | ||
const newDataSource = clone(props?.treeDataSource?.dataSource) | ||
tranverseTree(newDataSource || [], (dataItem, i, data) => { | ||
if (data[i].key === props.duplicateKey) (data || []).splice(i, 1) | ||
}) | ||
props.treeDataSource.dataSource = newDataSource | ||
}} | ||
/> | ||
</span> | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import React, { Fragment } from 'react' | ||
import { Tree, Button } from 'antd' | ||
import { PlusOutlined } from '@ant-design/icons' | ||
import { uid } from '@formily/shared' | ||
import { observer } from '@formily/reactive-react' | ||
import { usePrefix, TextWidget } from '@designable/react' | ||
import { Title } from './Title' | ||
import { Header } from './Header' | ||
import { tranverseTree } from './shared' | ||
import { ITreeDataSource, INodeItem } from './types' | ||
import './styles.less' | ||
|
||
export interface ITreePanelProps { | ||
treeDataSource: ITreeDataSource | ||
} | ||
|
||
export const TreePanel: React.FC<ITreePanelProps> = observer((props) => { | ||
const prefix = usePrefix('data-source-setter') | ||
const dropHanle = (info) => { | ||
const dropKey = info.node?.key | ||
const dragKey = info.dragNode?.key | ||
const dropPos = info.node.pos.split('-') | ||
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]) | ||
const data = [...props.treeDataSource.dataSource] | ||
// Find dragObject | ||
let dragObj | ||
tranverseTree(data, (item, index, arr) => { | ||
if (arr[index].key === dragKey) { | ||
arr.splice(index, 1) | ||
dragObj = item | ||
} | ||
}) | ||
|
||
if (!info.dropToGap) { | ||
// Drop on the content | ||
tranverseTree(data, (item) => { | ||
if (item.key === dropKey) { | ||
item.children = item.children || [] | ||
// where to insert 示例添加到头部,可以是随意位置 | ||
item.children.unshift(dragObj) | ||
} | ||
}) | ||
} else if ( | ||
(info.node.props.children || []).length > 0 && // Has children | ||
info.node.props.expanded && // Is expanded | ||
dropPosition === 1 // On the bottom gap | ||
) { | ||
tranverseTree(data, (item) => { | ||
if (item.key === dropKey) { | ||
item.children = item.children || [] | ||
// where to insert 示例添加到头部,可以是随意位置 | ||
item.children.unshift(dragObj) | ||
// in previous version, we use item.children.push(dragObj) to insert the | ||
// item to the tail of the children | ||
} | ||
}) | ||
} else { | ||
let ar | ||
let i | ||
tranverseTree(data, (item, index, arr) => { | ||
if (item.key === dropKey) { | ||
ar = arr | ||
i = index | ||
} | ||
}) | ||
if (dropPosition === -1) { | ||
ar.splice(i, 0, dragObj) | ||
} else { | ||
ar.splice(i + 1, 0, dragObj) | ||
} | ||
} | ||
props.treeDataSource.dataSource = data | ||
} | ||
return ( | ||
<Fragment> | ||
<Header | ||
title={ | ||
<TextWidget token="SettingComponents.DataSourceSetter.dataSourceTree" /> | ||
} | ||
extra={ | ||
<Button | ||
type="text" | ||
onClick={() => { | ||
const uuid = uid() | ||
props.treeDataSource.dataSource = | ||
props.treeDataSource.dataSource.concat({ | ||
key: uuid, | ||
duplicateKey: uuid, | ||
map: [ | ||
{ label: 'label', value: 'Label Text' }, | ||
{ label: 'value', value: 'Actual Value' }, | ||
], | ||
children: [], | ||
} as INodeItem) | ||
}} | ||
icon={<PlusOutlined />} | ||
> | ||
<TextWidget token="SettingComponents.DataSourceSetter.addNode" /> | ||
</Button> | ||
} | ||
/> | ||
<div className={`${prefix + '-layout-item-content'}`}> | ||
<Tree | ||
defaultExpandAll | ||
draggable | ||
showLine={{ showLeafIcon: false }} | ||
treeData={props.treeDataSource.dataSource} | ||
onDragEnter={() => {}} | ||
onDrop={dropHanle} | ||
titleRender={(titleProps: INodeItem) => ( | ||
<Title | ||
{...titleProps} | ||
treeDataSource={props.treeDataSource} | ||
></Title> | ||
)} | ||
onSelect={(selectedKeys) => { | ||
if (selectedKeys[0]) { | ||
props.treeDataSource.selectedkey = selectedKeys[0].toString() | ||
} | ||
}} | ||
></Tree> | ||
</div> | ||
</Fragment> | ||
) | ||
}) |
Oops, something went wrong.