(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());
+ // source.parent.removeProperty(source.name);
+ // 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(),
+ },
+ },
+ },
+ });
+ refresh();
+ },
+ });
+
+ return (
+
+ );
+}
+
+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);
+
+ // 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 (
+
+ );
+}
+
+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);
+ 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 (
+
+ );
+}
+
+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 (
+
+ );
+}
+
+export const Grid = ({ children }) => {
+ const { schema, refresh } = useSchema();
+ return (
+
+ {children}
+
+
+ );
+};
+
+export const GridRow = (props) => {
+ console.log('GridRow', props);
+ const { children } = props;
+ const form = useForm();
+ const { schema, refresh } = useSchema();
+ return (
+
+ {children}
+
+
+
+ );
+};
+
+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 (
+
+
+ {children}
+
+ );
+};
+
+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 (
+
+
+ {
+ schema.parent.removeProperty(schema.name);
+ refresh();
+ }}
+ />
+
+
+ {children}
+
+
+ );
+}
+
+function G({ children }) {
+ return {children}
;
+}
+
+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 (
+ {
+ forceUpdate(Math.random());
+ }}
+ >
+
+
+
+
+ );
+}
+
+export function Designer() {
+ const form = useMemo(() => createForm({}), []);
+ const [, forceUpdate] = useState(0);
+ return (
+
+
+
+
+ {(form) => {
+ return {JSON.stringify(form.values, null, 2)}
;
+ }}
+
+
+
+ );
+}
+
+export default Designer;
diff --git a/packages/client/src/fields/designer/style.less b/packages/client/src/fields/designer/style.less
new file mode 100644
index 000000000..fea7e0405
--- /dev/null
+++ b/packages/client/src/fields/designer/style.less
@@ -0,0 +1,57 @@
+.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;
+ }
+}
+