clean up the redundant examples
This commit is contained in:
parent
5e0277d451
commit
3c3ae5c348
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: Designer - 字段设计器
|
|
||||||
nav:
|
|
||||||
title: 组件
|
|
||||||
path: /client
|
|
||||||
group:
|
|
||||||
order: 1
|
|
||||||
title: 字段 - Fields
|
|
||||||
path: /client/fields
|
|
||||||
---
|
|
||||||
|
|
||||||
# Designer - 字段设计器
|
|
||||||
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import React from 'react';
|
|
||||||
import Designer from './'
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return (
|
|
||||||
<Designer/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,527 +0,0 @@
|
|||||||
import React, { useMemo, useContext, createContext, useState } from 'react';
|
|
||||||
import { Form, FormItem, FormLayout, Input } from '@formily/antd';
|
|
||||||
import {
|
|
||||||
observer,
|
|
||||||
FormProvider,
|
|
||||||
FormConsumer,
|
|
||||||
createSchemaField,
|
|
||||||
useField,
|
|
||||||
useFieldSchema,
|
|
||||||
useForm,
|
|
||||||
Schema,
|
|
||||||
SchemaExpressionScopeContext,
|
|
||||||
SchemaKey,
|
|
||||||
connect,
|
|
||||||
mapReadPretty,
|
|
||||||
mapProps,
|
|
||||||
} from '@formily/react';
|
|
||||||
import { createForm } from '@formily/core';
|
|
||||||
import { Row, Col, Button } from 'antd';
|
|
||||||
import { uid } from '@formily/shared';
|
|
||||||
import { useDrop, useDrag } from 'ahooks';
|
|
||||||
import './style.less';
|
|
||||||
import { DeleteOutlined, MenuOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
const SchemaEditorContext = createContext<Schema>(new Schema({}));
|
|
||||||
const SchemaRefreshContext = createContext(null);
|
|
||||||
|
|
||||||
function DropRow() {
|
|
||||||
const { schema: rowSchema, refresh } = useSchema();
|
|
||||||
const schema = rowSchema.parent;
|
|
||||||
const context = useContext(SchemaEditorContext);
|
|
||||||
function getSchema(names: any[]) {
|
|
||||||
const paths = [...names];
|
|
||||||
let schema: Schema = context;
|
|
||||||
while (paths.length) {
|
|
||||||
schema = schema.properties[paths.shift()];
|
|
||||||
}
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
const [props, { isHovering }] = useDrop({
|
|
||||||
onDom: (content, e) => {
|
|
||||||
console.log('paths', content);
|
|
||||||
const source = getSchema(content.paths);
|
|
||||||
// console.log({ paths: content.paths, source });
|
|
||||||
// schema.addProperty(source.name, source.toJSON());
|
|
||||||
// refresh();
|
|
||||||
|
|
||||||
const rowName = `row_${uid()}`;
|
|
||||||
const colName = `col_${uid()}`;
|
|
||||||
const fieldName = `field_${uid()}`;
|
|
||||||
schema.addProperty(rowName, {
|
|
||||||
type: 'void',
|
|
||||||
name: rowName,
|
|
||||||
'x-component': 'GridRow',
|
|
||||||
properties: {
|
|
||||||
[colName]: {
|
|
||||||
type: 'void',
|
|
||||||
name: colName,
|
|
||||||
'x-component': 'GridColumn',
|
|
||||||
'x-component-props': {
|
|
||||||
span: 24,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[source.name]: source.toJSON(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
source.parent.removeProperty(source.name);
|
|
||||||
refresh();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={isHovering ? 'drop-row active' : 'drop-row'} {...props} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropRowColumn() {
|
|
||||||
const form = useForm();
|
|
||||||
const { schema, refresh } = useSchema();
|
|
||||||
const context = useContext(SchemaEditorContext);
|
|
||||||
function getSchema(names: any[]) {
|
|
||||||
const paths = [...names];
|
|
||||||
let schema: Schema = context;
|
|
||||||
while (paths.length) {
|
|
||||||
schema = schema.properties[paths.shift()];
|
|
||||||
}
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
const [props, { isHovering }] = useDrop({
|
|
||||||
onDom: (content, e) => {
|
|
||||||
// console.log('paths', content);
|
|
||||||
const source = getSchema(content.paths);
|
|
||||||
const col = `col${uid()}`;
|
|
||||||
const blockName = `block${uid()}`;
|
|
||||||
const inputName = `input${uid()}`;
|
|
||||||
schema.addProperty(col, {
|
|
||||||
type: 'void',
|
|
||||||
name: col,
|
|
||||||
'x-component': 'GridColumn',
|
|
||||||
'x-component-props': {
|
|
||||||
labelCol: 6,
|
|
||||||
wrapperCol: 10,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[blockName]: source.toJSON(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const len = Object.keys(schema.properties).length;
|
|
||||||
const properties = schema.mapProperties((p) => p);
|
|
||||||
source.parent.removeProperty(source.name);
|
|
||||||
// schema.setProperties(newProperties);
|
|
||||||
// console.log(properties);
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
properties.forEach((p) => {
|
|
||||||
form.setFieldState(getFullPaths(p).join('.'), (state) => {
|
|
||||||
state.componentProps = {
|
|
||||||
span: 24 / len,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log({ paths: content.paths, source });
|
|
||||||
// schema.addProperty(source.name, source.toJSON());
|
|
||||||
// source.parent.removeProperty(source.name);
|
|
||||||
// refresh();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={isHovering ? `drop-column last active` : `drop-column last`}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropColumn() {
|
|
||||||
const form = useForm();
|
|
||||||
const { schema: columnSchema, refresh } = useSchema();
|
|
||||||
const schema = columnSchema.parent;
|
|
||||||
const context = useContext(SchemaEditorContext);
|
|
||||||
function getSchema(names: any[]) {
|
|
||||||
const paths = [...names];
|
|
||||||
let s: Schema = context;
|
|
||||||
while (paths.length) {
|
|
||||||
s = s.properties[paths.shift()];
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
const [props, { isHovering }] = useDrop({
|
|
||||||
onDom: (content, e) => {
|
|
||||||
// console.log('paths', content);
|
|
||||||
const source = getSchema(content.paths);
|
|
||||||
const col = `col${uid()}`;
|
|
||||||
const blockName = `block${uid()}`;
|
|
||||||
const inputName = `input${uid()}`;
|
|
||||||
schema.addProperty(col, {
|
|
||||||
type: 'void',
|
|
||||||
name: col,
|
|
||||||
'x-component': 'GridColumn',
|
|
||||||
'x-component-props': {
|
|
||||||
labelCol: 6,
|
|
||||||
wrapperCol: 10,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[blockName]: source.toJSON(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const len = Object.keys(schema.properties).length;
|
|
||||||
const properties = schema.mapProperties((p) => p);
|
|
||||||
|
|
||||||
// schema.setProperties(newProperties);
|
|
||||||
// console.log(properties);
|
|
||||||
source.parent.removeProperty(source.name);
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
properties.forEach((p) => {
|
|
||||||
form.setFieldState(getFullPaths(p).join('.'), (state) => {
|
|
||||||
state.componentProps = {
|
|
||||||
span: 24 / len,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log({ paths: content.paths, source });
|
|
||||||
// schema.addProperty(source.name, source.toJSON());
|
|
||||||
// refresh();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={isHovering ? `drop-column active` : `drop-column`}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function DropBlock() {
|
|
||||||
const { schema, refresh } = useSchema();
|
|
||||||
const context = useContext(SchemaEditorContext);
|
|
||||||
function getSchema(names: any[]) {
|
|
||||||
const paths = [...names];
|
|
||||||
let s: Schema = context;
|
|
||||||
while (paths.length) {
|
|
||||||
s = s.properties[paths.shift()];
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
const [props, { isHovering }] = useDrop({
|
|
||||||
onDom: (content, e) => {
|
|
||||||
const source = getSchema(content.paths);
|
|
||||||
console.log({ paths: content.paths, source });
|
|
||||||
schema.parent.addProperty(source.name, source.toJSON());
|
|
||||||
source.parent.removeProperty(source.name);
|
|
||||||
refresh();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={isHovering ? 'drop-block active' : 'drop-block'}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Grid = ({ children }) => {
|
|
||||||
const { schema, refresh } = useSchema();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{children}
|
|
||||||
<Button
|
|
||||||
block
|
|
||||||
type={'dashed'}
|
|
||||||
onClick={() => {
|
|
||||||
const rowName = `row_${uid()}`;
|
|
||||||
const colName = `col_${uid()}`;
|
|
||||||
const blockName = `block_${uid()}`;
|
|
||||||
const fieldName = `field_${uid()}`;
|
|
||||||
schema.addProperty(rowName, {
|
|
||||||
type: 'void',
|
|
||||||
name: rowName,
|
|
||||||
'x-component': 'GridRow',
|
|
||||||
properties: {
|
|
||||||
[colName]: {
|
|
||||||
type: 'void',
|
|
||||||
name: colName,
|
|
||||||
'x-component': 'GridColumn',
|
|
||||||
'x-component-props': {
|
|
||||||
span: 24,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[blockName]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridBlock',
|
|
||||||
'x-component-props': {},
|
|
||||||
'x-read-pretty': false,
|
|
||||||
properties: {
|
|
||||||
[fieldName]: {
|
|
||||||
type: 'string',
|
|
||||||
name: fieldName,
|
|
||||||
title: `输入框${fieldName}`,
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
+ 新增行
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GridRow = (props) => {
|
|
||||||
console.log('GridRow', props);
|
|
||||||
const { children } = props;
|
|
||||||
const form = useForm();
|
|
||||||
const { schema, refresh } = useSchema();
|
|
||||||
return (
|
|
||||||
<div className={'grid-row'} style={{ position: 'relative' }}>
|
|
||||||
<Row gutter={24}>{children}</Row>
|
|
||||||
<DropRowColumn />
|
|
||||||
<DropRow />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getFullPaths = (schema: Schema) => {
|
|
||||||
if (!schema) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const paths = [schema.name];
|
|
||||||
if (schema.parent.name) {
|
|
||||||
paths.unshift(...getFullPaths(schema.parent));
|
|
||||||
}
|
|
||||||
return paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
function useSchema() {
|
|
||||||
const context = useContext(SchemaEditorContext);
|
|
||||||
const refresh = useContext(SchemaRefreshContext);
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const paths = getFullPaths(fieldSchema);
|
|
||||||
console.log({ fieldSchema, paths, context });
|
|
||||||
let schema: Schema = context;
|
|
||||||
const names = [...paths];
|
|
||||||
while (names.length) {
|
|
||||||
schema = schema.properties[names.shift()];
|
|
||||||
}
|
|
||||||
return { schema, fieldSchema, refresh };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GridColumn = (props) => {
|
|
||||||
const { children } = props;
|
|
||||||
const { schema, refresh } = useSchema();
|
|
||||||
console.log('GridColumn', { props });
|
|
||||||
return (
|
|
||||||
<Col {...props}>
|
|
||||||
<DropColumn />
|
|
||||||
{children}
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function GridBlock({ children, ...props }) {
|
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const { schema, refresh } = useSchema();
|
|
||||||
const field = useField();
|
|
||||||
console.log('x-read-pretty', field.readPretty);
|
|
||||||
const getDragProps = useDrag({
|
|
||||||
onDragStart: (data, e) => {
|
|
||||||
// e.dataTransfer
|
|
||||||
// setDragging(data);
|
|
||||||
},
|
|
||||||
onDragEnd: (data) => {
|
|
||||||
// setDragging(null);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const paths = getFullPaths(schema);
|
|
||||||
console.log({ props, paths, schema, fieldSchema });
|
|
||||||
return (
|
|
||||||
<div className={'grid-block'} {...getDragProps({ paths })}>
|
|
||||||
<div className={'grid-block-actions'}>
|
|
||||||
<DeleteOutlined
|
|
||||||
onClick={() => {
|
|
||||||
schema.parent.removeProperty(schema.name);
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<MenuOutlined />
|
|
||||||
</div>
|
|
||||||
{children}
|
|
||||||
<DropBlock />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function G({ children }) {
|
|
||||||
return <div>{children}</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SchemaField = createSchemaField({
|
|
||||||
components: {
|
|
||||||
FormLayout,
|
|
||||||
FormItem,
|
|
||||||
Input,
|
|
||||||
Grid,
|
|
||||||
GridRow,
|
|
||||||
GridColumn,
|
|
||||||
GridBlock: (props) => {
|
|
||||||
const field = useField();
|
|
||||||
return React.createElement(field.readPretty ? G : GridBlock, props);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const schema = new Schema({
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
layout: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'FormLayout',
|
|
||||||
'x-component-props': {
|
|
||||||
layout: 'vertical',
|
|
||||||
// labelCol: 6,
|
|
||||||
// wrapperCol: 10,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
grid1: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
row1: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridRow',
|
|
||||||
'x-component-props': {
|
|
||||||
labelCol: 6,
|
|
||||||
wrapperCol: 10,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
col1: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridColumn',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
'x-component-props': {
|
|
||||||
labelCol: 6,
|
|
||||||
wrapperCol: 10,
|
|
||||||
span: 12,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
block1: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridBlock',
|
|
||||||
'x-component-props': {},
|
|
||||||
'x-read-pretty': false,
|
|
||||||
properties: {
|
|
||||||
input1: {
|
|
||||||
type: 'string',
|
|
||||||
title: '输入框1',
|
|
||||||
required: true,
|
|
||||||
'x-read-pretty': false,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
block2: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridBlock',
|
|
||||||
'x-component-props': {},
|
|
||||||
'x-read-pretty': false,
|
|
||||||
properties: {
|
|
||||||
input2: {
|
|
||||||
type: 'string',
|
|
||||||
title: '输入框2',
|
|
||||||
required: true,
|
|
||||||
'x-read-pretty': false,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
col2: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridColumn',
|
|
||||||
'x-component-props': {
|
|
||||||
span: 12,
|
|
||||||
labelCol: 6,
|
|
||||||
wrapperCol: 10,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
block3: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'GridBlock',
|
|
||||||
'x-component-props': {},
|
|
||||||
'x-read-pretty': false,
|
|
||||||
properties: {
|
|
||||||
input3: {
|
|
||||||
type: 'string',
|
|
||||||
title: '输入框3',
|
|
||||||
required: true,
|
|
||||||
'x-read-pretty': false,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function SchemaProvider(props) {
|
|
||||||
const { schema } = props;
|
|
||||||
const [, forceUpdate] = useState(0);
|
|
||||||
return (
|
|
||||||
<SchemaRefreshContext.Provider
|
|
||||||
value={() => {
|
|
||||||
forceUpdate(Math.random());
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SchemaEditorContext.Provider value={schema}>
|
|
||||||
<SchemaField schema={schema}></SchemaField>
|
|
||||||
</SchemaEditorContext.Provider>
|
|
||||||
</SchemaRefreshContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Designer() {
|
|
||||||
const form = useMemo(() => createForm({}), []);
|
|
||||||
const [, forceUpdate] = useState(0);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<FormProvider form={form}>
|
|
||||||
<SchemaProvider schema={schema} />
|
|
||||||
<FormConsumer>
|
|
||||||
{(form) => {
|
|
||||||
return <div>{JSON.stringify(form.values, null, 2)}</div>;
|
|
||||||
}}
|
|
||||||
</FormConsumer>
|
|
||||||
</FormProvider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Designer;
|
|
@ -1,57 +0,0 @@
|
|||||||
.drop-column {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -12px;
|
|
||||||
height: 100%;
|
|
||||||
width: 24px;
|
|
||||||
// border: 1px dashed rgb(232, 232, 232);
|
|
||||||
&.active {
|
|
||||||
background: #e6f7ff;
|
|
||||||
}
|
|
||||||
&.last {
|
|
||||||
left: auto;
|
|
||||||
right: -24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.drop-block {
|
|
||||||
height: 12px;
|
|
||||||
// background: #e6f7ff;
|
|
||||||
// pointer-events: none;
|
|
||||||
&.active {
|
|
||||||
background: #e6f7ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ant-formily-item + .drop-block {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 12px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-block {
|
|
||||||
position: relative;
|
|
||||||
padding-bottom: 1px;
|
|
||||||
.grid-block-actions {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1;
|
|
||||||
// display: none;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.grid-block-actions {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.drop-row {
|
|
||||||
height: 12px;
|
|
||||||
// background: #e6f7ff;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
&.active {
|
|
||||||
background: #e6f7ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user