feat(client): add designable test cases
This commit is contained in:
		
							parent
							
								
									be489996c3
								
							
						
					
					
						commit
						1a7f638f85
					
				@ -19,6 +19,7 @@ export interface IResource {
 | 
				
			|||||||
  create?: (params?: ActionParams) => Promise<any>;
 | 
					  create?: (params?: ActionParams) => Promise<any>;
 | 
				
			||||||
  update?: (params?: ActionParams) => Promise<any>;
 | 
					  update?: (params?: ActionParams) => Promise<any>;
 | 
				
			||||||
  destroy?: (params?: ActionParams) => Promise<any>;
 | 
					  destroy?: (params?: ActionParams) => Promise<any>;
 | 
				
			||||||
 | 
					  [key: string]: (params?: ActionParams) => Promise<any>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class APIClient {
 | 
					export class APIClient {
 | 
				
			||||||
 | 
				
			|||||||
@ -103,6 +103,96 @@ const FormBlockInitializerItem = itemWrap((props) => {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TestInitializerItem = itemWrap((props) => {
 | 
				
			||||||
 | 
					  const { insert } = props;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaInitializer.Item
 | 
				
			||||||
 | 
					      icon={<FormOutlined />}
 | 
				
			||||||
 | 
					      onClick={() => {
 | 
				
			||||||
 | 
					        insert({
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          name: uid(),
 | 
				
			||||||
 | 
					          'x-decorator': 'CardItem',
 | 
				
			||||||
 | 
					          'x-component': 'Grid',
 | 
				
			||||||
 | 
					          'x-uid': uid(),
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            row1: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					              'x-uid': uid(),
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                col11: {
 | 
				
			||||||
 | 
					                  type: 'void',
 | 
				
			||||||
 | 
					                  'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                  properties: {
 | 
				
			||||||
 | 
					                    block1: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '1',
 | 
				
			||||||
 | 
					                      'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					                      'x-component': 'Block',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    block2: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '2',
 | 
				
			||||||
 | 
					                      'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					                      'x-component': 'Block',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                col12: {
 | 
				
			||||||
 | 
					                  type: 'void',
 | 
				
			||||||
 | 
					                  'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                  properties: {
 | 
				
			||||||
 | 
					                    block3: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '3',
 | 
				
			||||||
 | 
					                      'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					                      'x-component': 'Block',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            row2: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					              'x-uid': uid(),
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                col21: {
 | 
				
			||||||
 | 
					                  type: 'void',
 | 
				
			||||||
 | 
					                  'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                  properties: {
 | 
				
			||||||
 | 
					                    block4: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '4',
 | 
				
			||||||
 | 
					                      'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					                      'x-component': 'Block',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                col22: {
 | 
				
			||||||
 | 
					                  type: 'void',
 | 
				
			||||||
 | 
					                  'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                  properties: {
 | 
				
			||||||
 | 
					                    block5: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '5',
 | 
				
			||||||
 | 
					                      'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					                      'x-component': 'Block',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      Test
 | 
				
			||||||
 | 
					    </SchemaInitializer.Item>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const AddGridBlockItem = observer((props: any) => {
 | 
					export const AddGridBlockItem = observer((props: any) => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <SchemaInitializer.Button
 | 
					    <SchemaInitializer.Button
 | 
				
			||||||
@ -123,6 +213,11 @@ export const AddGridBlockItem = observer((props: any) => {
 | 
				
			|||||||
              title: 'Form',
 | 
					              title: 'Form',
 | 
				
			||||||
              component: FormBlockInitializerItem,
 | 
					              component: FormBlockInitializerItem,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              type: 'item',
 | 
				
			||||||
 | 
					              title: 'Test',
 | 
				
			||||||
 | 
					              component: TestInitializerItem,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      ]}
 | 
					      ]}
 | 
				
			||||||
 | 
				
			|||||||
@ -74,8 +74,10 @@ const useCurrentFieldSchema = (path: string) => {
 | 
				
			|||||||
    remove() {
 | 
					    remove() {
 | 
				
			||||||
      schema &&
 | 
					      schema &&
 | 
				
			||||||
        remove(schema, {
 | 
					        remove(schema, {
 | 
				
			||||||
          breakComponent: 'Grid',
 | 
					          removeParentsIfNoChildren: true,
 | 
				
			||||||
          removeEmptyParents: true,
 | 
					          breakSchema: (s) => {
 | 
				
			||||||
 | 
					            return s['x-component'] === 'Grid';
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								packages/client/src/schema-component/antd/grid/Block.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								packages/client/src/schema-component/antd/grid/Block.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import { observer, useFieldSchema } from '@formily/react';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { DragHandler } from '../../';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Block = observer((props) => {
 | 
				
			||||||
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div style={{ marginBottom: 20, padding: '0 20px', height: 50, lineHeight: '50px', background: '#f1f1f1' }}>
 | 
				
			||||||
 | 
					      Block {fieldSchema.title}
 | 
				
			||||||
 | 
					      <DragHandler />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { observer, useFieldSchema } from '@formily/react';
 | 
					import { observer, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import { uid } from '@formily/shared';
 | 
					 | 
				
			||||||
import { BlockItem, DragHandler, Grid, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
 | 
					import { BlockItem, DragHandler, Grid, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,87 +12,151 @@ const Block = observer((props) => {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const schema = {
 | 
				
			||||||
 | 
					  _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					  version: '2.0',
 | 
				
			||||||
 | 
					  type: 'void',
 | 
				
			||||||
 | 
					  name: 'grid1',
 | 
				
			||||||
 | 
					  'x-decorator': 'CardItem',
 | 
				
			||||||
 | 
					  'x-component': 'Grid',
 | 
				
			||||||
 | 
					  properties: {
 | 
				
			||||||
 | 
					    row1: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        col11: {
 | 
				
			||||||
 | 
					          _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					          version: '2.0',
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            block1: {
 | 
				
			||||||
 | 
					              _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					              version: '2.0',
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '1',
 | 
				
			||||||
 | 
					              'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					              'x-component': 'Block',
 | 
				
			||||||
 | 
					              'x-uid': 'a9m97uffyku',
 | 
				
			||||||
 | 
					              'x-async': false,
 | 
				
			||||||
 | 
					              'x-index': 1,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            block2: {
 | 
				
			||||||
 | 
					              _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					              version: '2.0',
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '2.1',
 | 
				
			||||||
 | 
					              'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					              'x-component': 'Block',
 | 
				
			||||||
 | 
					              'x-uid': 'lensw462z8w',
 | 
				
			||||||
 | 
					              'x-async': false,
 | 
				
			||||||
 | 
					              'x-index': 2,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            block234: {
 | 
				
			||||||
 | 
					              _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					              version: '2.0',
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '2.2',
 | 
				
			||||||
 | 
					              'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					              'x-component': 'Block',
 | 
				
			||||||
 | 
					              'x-uid': 'lensw462z81',
 | 
				
			||||||
 | 
					              'x-async': false,
 | 
				
			||||||
 | 
					              'x-index': 3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          'x-uid': '4shevom50rl',
 | 
				
			||||||
 | 
					          'x-async': false,
 | 
				
			||||||
 | 
					          'x-index': 1,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        col12: {
 | 
				
			||||||
 | 
					          _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					          version: '2.0',
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            block3: {
 | 
				
			||||||
 | 
					              _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					              version: '2.0',
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '3',
 | 
				
			||||||
 | 
					              'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					              'x-component': 'Block',
 | 
				
			||||||
 | 
					              'x-uid': 'kp4kjknbs2l',
 | 
				
			||||||
 | 
					              'x-async': false,
 | 
				
			||||||
 | 
					              'x-index': 1,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          'x-uid': 'u7n3beze0gr',
 | 
				
			||||||
 | 
					          'x-async': false,
 | 
				
			||||||
 | 
					          'x-index': 2,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      'x-uid': 'qfl04eq71tt',
 | 
				
			||||||
 | 
					      'x-async': false,
 | 
				
			||||||
 | 
					      'x-index': 1,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    row2: {
 | 
				
			||||||
 | 
					      _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					      version: '2.0',
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        col21: {
 | 
				
			||||||
 | 
					          _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					          version: '2.0',
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            block4: {
 | 
				
			||||||
 | 
					              _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					              version: '2.0',
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '4',
 | 
				
			||||||
 | 
					              'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					              'x-component': 'Block',
 | 
				
			||||||
 | 
					              'x-uid': 'v5bd5kcyhat',
 | 
				
			||||||
 | 
					              'x-async': false,
 | 
				
			||||||
 | 
					              'x-index': 1,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          'x-uid': 'bwg0mv89atk',
 | 
				
			||||||
 | 
					          'x-async': false,
 | 
				
			||||||
 | 
					          'x-index': 1,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        col22: {
 | 
				
			||||||
 | 
					          _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					          version: '2.0',
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            block5: {
 | 
				
			||||||
 | 
					              _isJSONSchemaObject: true,
 | 
				
			||||||
 | 
					              version: '2.0',
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '5',
 | 
				
			||||||
 | 
					              'x-decorator': 'BlockItem',
 | 
				
			||||||
 | 
					              'x-component': 'Block',
 | 
				
			||||||
 | 
					              'x-uid': 'noh1flz5oqg',
 | 
				
			||||||
 | 
					              'x-async': false,
 | 
				
			||||||
 | 
					              'x-index': 1,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          'x-uid': 'oz0rypr2rlj',
 | 
				
			||||||
 | 
					          'x-async': false,
 | 
				
			||||||
 | 
					          'x-index': 2,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      'x-uid': '5igqpmvilz1',
 | 
				
			||||||
 | 
					      'x-async': false,
 | 
				
			||||||
 | 
					      'x-index': 2,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function App() {
 | 
					export default function App() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <SchemaComponentProvider components={{ Grid, Block, BlockItem }}>
 | 
					    <SchemaComponentProvider components={{ Grid, Block, BlockItem }}>
 | 
				
			||||||
      <SchemaComponent
 | 
					      <SchemaComponent schema={schema} />
 | 
				
			||||||
        schema={{
 | 
					 | 
				
			||||||
          type: 'void',
 | 
					 | 
				
			||||||
          name: 'grid1',
 | 
					 | 
				
			||||||
          'x-component': 'Grid',
 | 
					 | 
				
			||||||
          'x-uid': uid(),
 | 
					 | 
				
			||||||
          properties: {
 | 
					 | 
				
			||||||
            row1: {
 | 
					 | 
				
			||||||
              type: 'void',
 | 
					 | 
				
			||||||
              'x-component': 'Grid.Row',
 | 
					 | 
				
			||||||
              'x-uid': uid(),
 | 
					 | 
				
			||||||
              properties: {
 | 
					 | 
				
			||||||
                col11: {
 | 
					 | 
				
			||||||
                  type: 'void',
 | 
					 | 
				
			||||||
                  'x-component': 'Grid.Col',
 | 
					 | 
				
			||||||
                  properties: {
 | 
					 | 
				
			||||||
                    block1: {
 | 
					 | 
				
			||||||
                      type: 'void',
 | 
					 | 
				
			||||||
                      title: '1',
 | 
					 | 
				
			||||||
                      'x-decorator': 'BlockItem',
 | 
					 | 
				
			||||||
                      'x-component': 'Block',
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    block2: {
 | 
					 | 
				
			||||||
                      type: 'void',
 | 
					 | 
				
			||||||
                      title: '2',
 | 
					 | 
				
			||||||
                      'x-decorator': 'BlockItem',
 | 
					 | 
				
			||||||
                      'x-component': 'Block',
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                col12: {
 | 
					 | 
				
			||||||
                  type: 'void',
 | 
					 | 
				
			||||||
                  'x-component': 'Grid.Col',
 | 
					 | 
				
			||||||
                  properties: {
 | 
					 | 
				
			||||||
                    block3: {
 | 
					 | 
				
			||||||
                      type: 'void',
 | 
					 | 
				
			||||||
                      title: '3',
 | 
					 | 
				
			||||||
                      'x-decorator': 'BlockItem',
 | 
					 | 
				
			||||||
                      'x-component': 'Block',
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            row2: {
 | 
					 | 
				
			||||||
              type: 'void',
 | 
					 | 
				
			||||||
              'x-component': 'Grid.Row',
 | 
					 | 
				
			||||||
              'x-uid': uid(),
 | 
					 | 
				
			||||||
              properties: {
 | 
					 | 
				
			||||||
                col21: {
 | 
					 | 
				
			||||||
                  type: 'void',
 | 
					 | 
				
			||||||
                  'x-component': 'Grid.Col',
 | 
					 | 
				
			||||||
                  properties: {
 | 
					 | 
				
			||||||
                    block4: {
 | 
					 | 
				
			||||||
                      type: 'void',
 | 
					 | 
				
			||||||
                      title: '4',
 | 
					 | 
				
			||||||
                      'x-decorator': 'BlockItem',
 | 
					 | 
				
			||||||
                      'x-component': 'Block',
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                col22: {
 | 
					 | 
				
			||||||
                  type: 'void',
 | 
					 | 
				
			||||||
                  'x-component': 'Grid.Col',
 | 
					 | 
				
			||||||
                  properties: {
 | 
					 | 
				
			||||||
                    block5: {
 | 
					 | 
				
			||||||
                      type: 'void',
 | 
					 | 
				
			||||||
                      title: '5',
 | 
					 | 
				
			||||||
                      'x-decorator': 'BlockItem',
 | 
					 | 
				
			||||||
                      'x-component': 'Block',
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </SchemaComponentProvider>
 | 
					    </SchemaComponentProvider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,20 +1,44 @@
 | 
				
			|||||||
import { ISchema } from '@formily/react';
 | 
					import { ISchema, observer, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import { uid } from '@formily/shared';
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
import { CardItem, Form, Grid, Markdown, SchemaComponent, SchemaComponentProvider, VoidTable } from '@nocobase/client';
 | 
					import {
 | 
				
			||||||
 | 
					  BlockItem,
 | 
				
			||||||
 | 
					  CardItem,
 | 
				
			||||||
 | 
					  DragHandler,
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Grid,
 | 
				
			||||||
 | 
					  Markdown,
 | 
				
			||||||
 | 
					  SchemaComponent,
 | 
				
			||||||
 | 
					  SchemaComponentProvider,
 | 
				
			||||||
 | 
					  VoidTable
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Block = observer((props) => {
 | 
				
			||||||
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div style={{ marginBottom: 20, padding: '0 20px', height: 50, lineHeight: '50px', background: '#f1f1f1' }}>
 | 
				
			||||||
 | 
					      Block {fieldSchema.title}
 | 
				
			||||||
 | 
					      <DragHandler />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const schema: ISchema = {
 | 
					const schema: ISchema = {
 | 
				
			||||||
  type: 'void',
 | 
					  type: 'object',
 | 
				
			||||||
  name: 'grid1',
 | 
					  properties: {
 | 
				
			||||||
  'x-component': 'Grid',
 | 
					    grid: {
 | 
				
			||||||
  'x-item-initializer': 'Grid.AddBlockItem',
 | 
					      type: 'void',
 | 
				
			||||||
  'x-uid': uid(),
 | 
					      'x-component': 'Grid',
 | 
				
			||||||
  properties: {},
 | 
					      'x-item-initializer': 'Grid.AddBlockItem',
 | 
				
			||||||
 | 
					      'x-uid': uid(),
 | 
				
			||||||
 | 
					      properties: {},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function App() {
 | 
					export default function App() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <SchemaComponentProvider components={{ Grid, CardItem, Markdown, Form, VoidTable }}>
 | 
					    <SchemaComponentProvider components={{ BlockItem, Block, Grid, CardItem, Markdown, Form, VoidTable }}>
 | 
				
			||||||
      <SchemaComponent schema={schema} />
 | 
					      <SchemaComponent schema={schema} />
 | 
				
			||||||
    </SchemaComponentProvider>
 | 
					    </SchemaComponentProvider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1,3 @@
 | 
				
			|||||||
 | 
					export * from './Block';
 | 
				
			||||||
export * from './Grid';
 | 
					export * from './Grid';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,6 @@ const useDragEnd = () => {
 | 
				
			|||||||
  const { refresh } = useDesignable();
 | 
					  const { refresh } = useDesignable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return ({ active, over }: DragEndEvent) => {
 | 
					  return ({ active, over }: DragEndEvent) => {
 | 
				
			||||||
    console.log({ active, over });
 | 
					 | 
				
			||||||
    const activeSchema = active?.data?.current?.schema;
 | 
					    const activeSchema = active?.data?.current?.schema;
 | 
				
			||||||
    const overSchema = over?.data?.current?.schema;
 | 
					    const overSchema = over?.data?.current?.schema;
 | 
				
			||||||
    const insertAdjacent = over?.data?.current?.insertAdjacent;
 | 
					    const insertAdjacent = over?.data?.current?.insertAdjacent;
 | 
				
			||||||
@ -35,7 +34,7 @@ const useDragEnd = () => {
 | 
				
			|||||||
    if (insertAdjacent) {
 | 
					    if (insertAdjacent) {
 | 
				
			||||||
      dn.insertAdjacent(insertAdjacent, activeSchema, {
 | 
					      dn.insertAdjacent(insertAdjacent, activeSchema, {
 | 
				
			||||||
        wrap: wrapSchema,
 | 
					        wrap: wrapSchema,
 | 
				
			||||||
        removeEmptyParents: true,
 | 
					        removeParentsIfNoChildren: true,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -34,16 +34,11 @@ export const Sortable = (props: any) => {
 | 
				
			|||||||
export const SortableItem: React.FC<any> = observer((props) => {
 | 
					export const SortableItem: React.FC<any> = observer((props) => {
 | 
				
			||||||
  const field = useField();
 | 
					  const field = useField();
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
  const onInsertAdjacent = ({ dn, orginDraggedParentSchema }) => {
 | 
					 | 
				
			||||||
    dn.removeIfChildrenEmpty(orginDraggedParentSchema, {
 | 
					 | 
				
			||||||
      removeEmptyParents: true,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Sortable
 | 
					    <Sortable
 | 
				
			||||||
      {...props}
 | 
					      {...props}
 | 
				
			||||||
      id={field.address.toString()}
 | 
					      id={field.address.toString()}
 | 
				
			||||||
      data={{ insertAdjacent: 'afterEnd', onInsertAdjacent, schema: fieldSchema }}
 | 
					      data={{ insertAdjacent: 'afterEnd', schema: fieldSchema }}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {props.children}
 | 
					      {props.children}
 | 
				
			||||||
    </Sortable>
 | 
					    </Sortable>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,453 @@
 | 
				
			|||||||
 | 
					import { Schema } from '@formily/react';
 | 
				
			||||||
 | 
					import { createDesignable, Designable } from '../useDesignable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('createDesignable', () => {
 | 
				
			||||||
 | 
					  let dn: Designable;
 | 
				
			||||||
 | 
					  let schema: Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    schema = new Schema({
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      name: 'global',
 | 
				
			||||||
 | 
					      'x-uid': 'global',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        current: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-uid': 'current',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            child: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              'x-uid': 'child',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.current,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('insert a new node', () => {
 | 
				
			||||||
 | 
					    test('insertBeforeBegin', () => {
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					        name: 'abc',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.toJSON()).toMatchObject({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'global',
 | 
				
			||||||
 | 
					        'x-uid': 'global',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          abc: {
 | 
				
			||||||
 | 
					            name: 'abc',
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          current: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            name: 'current',
 | 
				
			||||||
 | 
					            'x-uid': 'current',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              child: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-uid': 'child',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.properties.abc['x-uid']).toBeDefined();
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['abc', 'current']);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertAfterBegin', () => {
 | 
				
			||||||
 | 
					      dn.insertAfterBegin({
 | 
				
			||||||
 | 
					        name: 'abc',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties.current.properties)).toEqual(['abc', 'child']);
 | 
				
			||||||
 | 
					      expect(schema.toJSON()).toMatchObject({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'global',
 | 
				
			||||||
 | 
					        'x-uid': 'global',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          current: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            name: 'current',
 | 
				
			||||||
 | 
					            'x-uid': 'current',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              abc: {
 | 
				
			||||||
 | 
					                name: 'abc',
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              child: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-uid': 'child',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.properties.current.properties.abc['x-uid']).toBeDefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertBeforeEnd', () => {
 | 
				
			||||||
 | 
					      dn.insertBeforeEnd({
 | 
				
			||||||
 | 
					        name: 'abc',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.toJSON()).toMatchObject({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'global',
 | 
				
			||||||
 | 
					        'x-uid': 'global',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          current: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            name: 'current',
 | 
				
			||||||
 | 
					            'x-uid': 'current',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              child: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-uid': 'child',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              abc: {
 | 
				
			||||||
 | 
					                name: 'abc',
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.properties.current.properties.abc['x-uid']).toBeDefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertAfterEnd', () => {
 | 
				
			||||||
 | 
					      dn.insertAfterEnd({
 | 
				
			||||||
 | 
					        name: 'abc',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.toJSON()).toMatchObject({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'global',
 | 
				
			||||||
 | 
					        'x-uid': 'global',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          current: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            name: 'current',
 | 
				
			||||||
 | 
					            'x-uid': 'current',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              child: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-uid': 'child',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          abc: {
 | 
				
			||||||
 | 
					            name: 'abc',
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema.properties.abc['x-uid']).toBeDefined();
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['current', 'abc']);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('move an existing node', () => {
 | 
				
			||||||
 | 
					    test('insertBeforeBegin', () => {
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin(schema.properties.current.properties.child);
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['child', 'current']);
 | 
				
			||||||
 | 
					      expect(schema.properties.current?.properties?.child).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertBeforeBegin', () => {
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'a1',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'a2',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'a3',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['a1', 'a2', 'a3', 'current']);
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin(schema.properties.a2);
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['a1', 'a3', 'a2', 'current']);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertAfterBegin', () => {
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					        name: 'a1',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.insertAfterBegin(schema.properties.a1);
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties.current.properties)).toEqual(['a1', 'child']);
 | 
				
			||||||
 | 
					      expect(schema.properties.a1).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertBeforeEnd', () => {
 | 
				
			||||||
 | 
					      dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					        name: 'a1',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.insertBeforeEnd(schema.properties.a1);
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties.current.properties)).toEqual(['child', 'a1']);
 | 
				
			||||||
 | 
					      expect(schema.properties.a1).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertAfterEnd', () => {
 | 
				
			||||||
 | 
					      dn.insertAfterEnd(schema.properties.current.properties.child);
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['current', 'child']);
 | 
				
			||||||
 | 
					      expect(schema.properties.current?.properties?.child).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('insertAfterEnd', () => {
 | 
				
			||||||
 | 
					      dn.insertAfterEnd({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'a1',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.insertAfterEnd({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'a2',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.insertAfterEnd({
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'a3',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['current', 'a3', 'a2', 'a1']);
 | 
				
			||||||
 | 
					      dn.insertAfterEnd(schema.properties.a2);
 | 
				
			||||||
 | 
					      expect(Object.keys(schema.properties)).toEqual(['current', 'a2', 'a3', 'a1']);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('removeIfNoChildren', () => {
 | 
				
			||||||
 | 
					    test('has child nodes', () => {
 | 
				
			||||||
 | 
					      dn.removeIfNoChildren(schema.properties.current);
 | 
				
			||||||
 | 
					      expect(schema.properties.current).toBeDefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('no child nodes', () => {
 | 
				
			||||||
 | 
					      dn.removeIfNoChildren(schema.properties.current.properties.child);
 | 
				
			||||||
 | 
					      expect(schema.properties.current?.properties?.child).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('remove', () => {
 | 
				
			||||||
 | 
					    test('without schema', () => {
 | 
				
			||||||
 | 
					      dn.remove();
 | 
				
			||||||
 | 
					      expect(schema?.properties?.current).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('without options', () => {
 | 
				
			||||||
 | 
					      dn.remove(schema.properties.current.properties.child);
 | 
				
			||||||
 | 
					      expect(schema.properties.current).toBeDefined();
 | 
				
			||||||
 | 
					      expect(schema.properties.current?.properties?.child).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('removeParentsIfNoChildren + breakSchema json', () => {
 | 
				
			||||||
 | 
					      dn.remove(schema.properties.current.properties.child, {
 | 
				
			||||||
 | 
					        removeParentsIfNoChildren: true,
 | 
				
			||||||
 | 
					        breakSchema: {
 | 
				
			||||||
 | 
					          'x-uid': 'global',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema?.properties?.current).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test('removeParentsIfNoChildren + breakSchema function', () => {
 | 
				
			||||||
 | 
					      dn.remove(schema.properties.current.properties.child, {
 | 
				
			||||||
 | 
					        removeParentsIfNoChildren: true,
 | 
				
			||||||
 | 
					        breakSchema: (s) => s['x-uid'] === 'global',
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(schema?.properties?.current).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('x-index', () => {
 | 
				
			||||||
 | 
					  let dn: Designable;
 | 
				
			||||||
 | 
					  let schema: Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    schema = new Schema({
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      name: 'col1',
 | 
				
			||||||
 | 
					      'x-uid': 'col1',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        block1: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-index': 1,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        block2: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-index': 2,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        block3: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-index': 3,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        block4: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-index': 4,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        block5: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-index': 5,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertBeforeBeginOrAfterEnd', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.block2,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    dn.insertBeforeBeginOrAfterEnd(schema.properties.block5);
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties)).toEqual(['block1', 'block5', 'block2', 'block3', 'block4']);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertBeforeBegin', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.block2,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    dn.insertBeforeBegin({
 | 
				
			||||||
 | 
					      name: 'block0',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties)).toEqual(['block1', 'block0', 'block2', 'block3', 'block4', 'block5']);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertAfterEnd', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.block2,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    dn.insertAfterEnd({
 | 
				
			||||||
 | 
					      name: 'block0',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties)).toEqual(['block1', 'block2', 'block0', 'block3', 'block4', 'block5']);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertAfterBegin', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    dn.insertAfterBegin({
 | 
				
			||||||
 | 
					      name: 'block0',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties)).toEqual(['block0', 'block1', 'block2', 'block3', 'block4', 'block5']);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertBeforeEnd', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    dn.insertBeforeEnd({
 | 
				
			||||||
 | 
					      name: 'block0',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties)).toEqual(['block1', 'block2', 'block3', 'block4', 'block5', 'block0']);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('wrap', () => {
 | 
				
			||||||
 | 
					  let dn: Designable;
 | 
				
			||||||
 | 
					  let schema: Schema;
 | 
				
			||||||
 | 
					  const colWrap = (s) => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      name: 'col12',
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-uid': 'col12',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        [s.name]: s,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const rowWrap = (s) => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      name: 'row2',
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-uid': 'row2',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        col21: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-uid': 'col21',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            [s.name]: s,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    schema = new Schema({
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      name: 'grid1',
 | 
				
			||||||
 | 
					      'x-uid': 'grid1',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        row1: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-uid': 'row1',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            col11: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              'x-uid': 'col11',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                block1: {
 | 
				
			||||||
 | 
					                  type: 'void',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertBeforeBegin', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.row1.properties.col11,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const s = {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      name: 'block2',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    dn.insertBeforeBegin(s, {
 | 
				
			||||||
 | 
					      wrap: colWrap,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties.row1.properties)).toEqual(['col12', 'col11']);
 | 
				
			||||||
 | 
					    expect(schema.properties.row1.properties.col12.properties.block2).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('insertAfterEnd', () => {
 | 
				
			||||||
 | 
					    dn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.row1.properties.col11,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const s = {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      name: 'block2',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    dn.insertAfterEnd(s, {
 | 
				
			||||||
 | 
					      wrap: colWrap,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties.row1.properties)).toEqual(['col11', 'col12']);
 | 
				
			||||||
 | 
					    expect(schema.properties.row1.properties.col12.properties.block2).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('removeParentsIfNoChildren', () => {
 | 
				
			||||||
 | 
					    const coldn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema.properties.row1.properties.col11,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const s = {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      name: 'block2',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    coldn.insertAfterEnd(s, { wrap: colWrap });
 | 
				
			||||||
 | 
					    const griddn = createDesignable({
 | 
				
			||||||
 | 
					      current: schema,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    griddn.insertBeforeEnd(schema.properties.row1.properties.col12.properties.block2, {
 | 
				
			||||||
 | 
					      wrap: rowWrap,
 | 
				
			||||||
 | 
					      removeParentsIfNoChildren: true,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties.row1.properties)).toEqual(['col11']);
 | 
				
			||||||
 | 
					    expect(Object.keys(schema.properties.row2.properties)).toEqual(['col21']);
 | 
				
			||||||
 | 
					    expect(schema.properties.row2.properties.col21.properties.block2).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -3,6 +3,7 @@ import { uid } from '@formily/shared';
 | 
				
			|||||||
import get from 'lodash/get';
 | 
					import get from 'lodash/get';
 | 
				
			||||||
import set from 'lodash/set';
 | 
					import set from 'lodash/set';
 | 
				
			||||||
import React, { useContext } from 'react';
 | 
					import React, { useContext } from 'react';
 | 
				
			||||||
 | 
					import { useAPIClient } from '../../api-client';
 | 
				
			||||||
import { SchemaComponentContext } from '../context';
 | 
					import { SchemaComponentContext } from '../context';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface CreateDesignableProps {
 | 
					interface CreateDesignableProps {
 | 
				
			||||||
@ -20,12 +21,14 @@ type Position = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
interface InsertAdjacentOptions {
 | 
					interface InsertAdjacentOptions {
 | 
				
			||||||
  wrap?: (s: ISchema) => ISchema;
 | 
					  wrap?: (s: ISchema) => ISchema;
 | 
				
			||||||
  removeEmptyParents?: boolean;
 | 
					  removeParentsIfNoChildren?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type BreakFn = (s: ISchema) => boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface RemoveOptions {
 | 
					interface RemoveOptions {
 | 
				
			||||||
  removeEmptyParents?: boolean;
 | 
					  removeParentsIfNoChildren?: boolean;
 | 
				
			||||||
  breakComponent?: string;
 | 
					  breakSchema?: ISchema | BreakFn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const generateUid = (s: ISchema) => {
 | 
					const generateUid = (s: ISchema) => {
 | 
				
			||||||
@ -76,7 +79,7 @@ export class Designable {
 | 
				
			|||||||
    if (!this.events[name]) {
 | 
					    if (!this.events[name]) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.events[name].forEach((fn) => fn.bind(this)(...args));
 | 
					    this.events[name].forEach((fn) => fn.bind(this)(this.current, ...args));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  insertAdjacent(position: Position, schema: ISchema, options: InsertAdjacentOptions = {}) {
 | 
					  insertAdjacent(position: Position, schema: ISchema, options: InsertAdjacentOptions = {}) {
 | 
				
			||||||
@ -92,17 +95,16 @@ export class Designable {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  removeIfChildrenEmpty(schema?: Schema) {
 | 
					  removeIfNoChildren(schema?: Schema) {
 | 
				
			||||||
    if (!schema) {
 | 
					    if (!schema) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let s = schema;
 | 
					    let s = schema;
 | 
				
			||||||
    const count = Object.keys(s.properties || {}).length;
 | 
					    const count = Object.keys(s.properties || {}).length;
 | 
				
			||||||
    console.log('removeIfChildrenEmpty', count, s.properties);
 | 
					 | 
				
			||||||
    if (count > 0) {
 | 
					    if (count > 0) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let removed;
 | 
					    let removed: Schema;
 | 
				
			||||||
    while (s.parent) {
 | 
					    while (s.parent) {
 | 
				
			||||||
      removed = s.parent.removeProperty(s.name);
 | 
					      removed = s.parent.removeProperty(s.name);
 | 
				
			||||||
      const count = Object.keys(s.parent.properties || {}).length;
 | 
					      const count = Object.keys(s.parent.properties || {}).length;
 | 
				
			||||||
@ -111,18 +113,42 @@ export class Designable {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      s = s.parent;
 | 
					      s = s.parent;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return removed;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  remove(schema?: Schema, options: RemoveOptions = {}) {
 | 
					  remove(schema?: Schema, options: RemoveOptions = {}) {
 | 
				
			||||||
    const { removeEmptyParents, breakComponent } = options;
 | 
					    const { removeParentsIfNoChildren, breakSchema } = options;
 | 
				
			||||||
    let s = schema || this.current;
 | 
					    let s = schema || this.current;
 | 
				
			||||||
    let removed;
 | 
					    let removed;
 | 
				
			||||||
 | 
					    const matchSchema = (source: ISchema, target: ISchema) => {
 | 
				
			||||||
 | 
					      if (!source || !target) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      for (const key in target) {
 | 
				
			||||||
 | 
					        if (Object.prototype.hasOwnProperty.call(target, key)) {
 | 
				
			||||||
 | 
					          const value = target[key];
 | 
				
			||||||
 | 
					          if (value !== source?.[key]) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    while (s.parent) {
 | 
					    while (s.parent) {
 | 
				
			||||||
      removed = s.parent.removeProperty(s.name);
 | 
					      removed = s.parent.removeProperty(s.name);
 | 
				
			||||||
      if (!removeEmptyParents) {
 | 
					      if (!removeParentsIfNoChildren) {
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (s?.parent?.['x-component'] === breakComponent) {
 | 
					      if (typeof breakSchema === 'function') {
 | 
				
			||||||
 | 
					        if (breakSchema(s?.parent)) {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        if (matchSchema(s?.parent, breakSchema)) {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (s?.parent?.['x-component'] === breakSchema) {
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      const count = Object.keys(s.parent.properties || {}).length;
 | 
					      const count = Object.keys(s.parent.properties || {}).length;
 | 
				
			||||||
@ -131,7 +157,7 @@ export class Designable {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      s = s.parent;
 | 
					      s = s.parent;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.emit('afterRemove', removed);
 | 
					    this.emit('afterRemove', removed, options);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  insertBeforeBeginOrAfterEnd(schema: ISchema, options: InsertAdjacentOptions = {}) {
 | 
					  insertBeforeBeginOrAfterEnd(schema: ISchema, options: InsertAdjacentOptions = {}) {
 | 
				
			||||||
@ -164,33 +190,38 @@ export class Designable {
 | 
				
			|||||||
    if (!Schema.isSchemaInstance(this.current)) {
 | 
					    if (!Schema.isSchemaInstance(this.current)) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
					    const opts = {};
 | 
				
			||||||
    const properties = {};
 | 
					    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
				
			||||||
    let start = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (Schema.isSchemaInstance(schema)) {
 | 
					    if (Schema.isSchemaInstance(schema)) {
 | 
				
			||||||
      schema.parent.removeProperty(schema.name);
 | 
					      schema.parent.removeProperty(schema.name);
 | 
				
			||||||
      if (removeEmptyParents) {
 | 
					      if (removeParentsIfNoChildren) {
 | 
				
			||||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
					        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const properties = {};
 | 
				
			||||||
 | 
					    let start = false;
 | 
				
			||||||
 | 
					    let order = 0;
 | 
				
			||||||
 | 
					    let newOrder = 0;
 | 
				
			||||||
    this.current.parent.mapProperties((property, key) => {
 | 
					    this.current.parent.mapProperties((property, key) => {
 | 
				
			||||||
      if (key === this.current.name) {
 | 
					      if (key === this.current.name) {
 | 
				
			||||||
 | 
					        newOrder = order;
 | 
				
			||||||
        start = true;
 | 
					        start = true;
 | 
				
			||||||
 | 
					        ++order;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      property['x-index'] = order;
 | 
				
			||||||
 | 
					      ++order;
 | 
				
			||||||
      if (start) {
 | 
					      if (start) {
 | 
				
			||||||
        properties[key] = property;
 | 
					        properties[key] = property;
 | 
				
			||||||
        this.current.parent.removeProperty(key);
 | 
					        this.current.parent.removeProperty(key);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.prepareProperty(schema);
 | 
					    this.prepareProperty(schema);
 | 
				
			||||||
    const wrapped = wrap(schema);
 | 
					    const wrapped = wrap(schema);
 | 
				
			||||||
    const s = this.current.parent.addProperty(wrapped.name, wrapped);
 | 
					    const s = this.current.parent.addProperty(wrapped.name || uid(), wrapped);
 | 
				
			||||||
 | 
					    s['x-index'] = newOrder;
 | 
				
			||||||
    s.parent = this.current.parent;
 | 
					    s.parent = this.current.parent;
 | 
				
			||||||
    this.current.parent.setProperties(properties);
 | 
					    this.current.parent.setProperties(properties);
 | 
				
			||||||
    this.emit('afterInsertAdjacent', 'beforeBegin', s);
 | 
					    this.emit('afterInsertAdjacent', 'beforeBegin', s, opts);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -203,24 +234,29 @@ export class Designable {
 | 
				
			|||||||
    if (!Schema.isSchemaInstance(this.current)) {
 | 
					    if (!Schema.isSchemaInstance(this.current)) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
					    const opts = {};
 | 
				
			||||||
 | 
					    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
				
			||||||
    if (Schema.isSchemaInstance(schema)) {
 | 
					    if (Schema.isSchemaInstance(schema)) {
 | 
				
			||||||
      schema.parent.removeProperty(schema.name);
 | 
					      schema.parent.removeProperty(schema.name);
 | 
				
			||||||
      if (removeEmptyParents) {
 | 
					      if (removeParentsIfNoChildren) {
 | 
				
			||||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
					        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const properties = {};
 | 
					    const properties = {};
 | 
				
			||||||
    this.current.mapProperties((schema, key) => {
 | 
					    let order = 1;
 | 
				
			||||||
      properties[key] = schema;
 | 
					    this.current.mapProperties((s, key) => {
 | 
				
			||||||
 | 
					      s['x-index'] = order;
 | 
				
			||||||
 | 
					      ++order;
 | 
				
			||||||
 | 
					      properties[key] = s;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.current.properties = {};
 | 
					    this.current.properties = {};
 | 
				
			||||||
    this.prepareProperty(schema);
 | 
					    this.prepareProperty(schema);
 | 
				
			||||||
    const wrapped = wrap(schema);
 | 
					    const wrapped = wrap(schema);
 | 
				
			||||||
    const s = this.current.addProperty(wrapped.name, wrapped);
 | 
					    const s = this.current.addProperty(wrapped.name || uid(), wrapped);
 | 
				
			||||||
 | 
					    s['x-index'] = 0;
 | 
				
			||||||
    s.parent = this.current;
 | 
					    s.parent = this.current;
 | 
				
			||||||
    this.current.setProperties(properties);
 | 
					    this.current.setProperties(properties);
 | 
				
			||||||
    this.emit('afterInsertAdjacent', 'afterBegin', s);
 | 
					    this.emit('afterInsertAdjacent', 'afterBegin', s, opts);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -233,18 +269,19 @@ export class Designable {
 | 
				
			|||||||
    if (!Schema.isSchemaInstance(this.current)) {
 | 
					    if (!Schema.isSchemaInstance(this.current)) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
					    const opts = {};
 | 
				
			||||||
 | 
					    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
				
			||||||
    if (Schema.isSchemaInstance(schema)) {
 | 
					    if (Schema.isSchemaInstance(schema)) {
 | 
				
			||||||
      schema.parent.removeProperty(schema.name);
 | 
					      schema.parent.removeProperty(schema.name);
 | 
				
			||||||
      if (removeEmptyParents) {
 | 
					      if (removeParentsIfNoChildren) {
 | 
				
			||||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
					        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.prepareProperty(schema);
 | 
					    this.prepareProperty(schema);
 | 
				
			||||||
    const wrapped = wrap(schema);
 | 
					    const wrapped = wrap(schema);
 | 
				
			||||||
    const s = this.current.addProperty(wrapped.name || uid(), wrapped);
 | 
					    const s = this.current.addProperty(wrapped.name || uid(), wrapped);
 | 
				
			||||||
    s.parent = this.current;
 | 
					    s.parent = this.current;
 | 
				
			||||||
    this.emit('afterInsertAdjacent', 'beforeEnd', s);
 | 
					    this.emit('afterInsertAdjacent', 'beforeEnd', s, opts);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -254,22 +291,29 @@ export class Designable {
 | 
				
			|||||||
    if (!Schema.isSchemaInstance(this.current)) {
 | 
					    if (!Schema.isSchemaInstance(this.current)) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const properties = {};
 | 
					    const opts = {};
 | 
				
			||||||
    let start = false;
 | 
					    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
				
			||||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
					 | 
				
			||||||
    if (Schema.isSchemaInstance(schema)) {
 | 
					    if (Schema.isSchemaInstance(schema)) {
 | 
				
			||||||
      schema.parent.removeProperty(schema.name);
 | 
					      schema.parent.removeProperty(schema.name);
 | 
				
			||||||
      console.log('insertAfterEnd', removeEmptyParents);
 | 
					      if (removeParentsIfNoChildren) {
 | 
				
			||||||
      if (removeEmptyParents) {
 | 
					        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
				
			||||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      schema.parent = null;
 | 
					      schema.parent = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let order = 0;
 | 
				
			||||||
 | 
					    let newOrder = 0;
 | 
				
			||||||
 | 
					    let start = false;
 | 
				
			||||||
 | 
					    const properties = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.current.parent.mapProperties((property, key) => {
 | 
					    this.current.parent.mapProperties((property, key) => {
 | 
				
			||||||
 | 
					      property['x-index'] = order;
 | 
				
			||||||
      if (key === this.current.name) {
 | 
					      if (key === this.current.name) {
 | 
				
			||||||
 | 
					        ++order;
 | 
				
			||||||
 | 
					        newOrder = order;
 | 
				
			||||||
        start = true;
 | 
					        start = true;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      ++order;
 | 
				
			||||||
      if (start && key !== this.current.name) {
 | 
					      if (start && key !== this.current.name) {
 | 
				
			||||||
        properties[key] = property;
 | 
					        properties[key] = property;
 | 
				
			||||||
        this.current.parent.removeProperty(key);
 | 
					        this.current.parent.removeProperty(key);
 | 
				
			||||||
@ -277,13 +321,12 @@ export class Designable {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.prepareProperty(schema);
 | 
					    this.prepareProperty(schema);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const wrapped = wrap(schema);
 | 
					    const wrapped = wrap(schema);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const s = this.current.parent.addProperty(wrapped.name || uid(), wrapped);
 | 
					    const s = this.current.parent.addProperty(wrapped.name || uid(), wrapped);
 | 
				
			||||||
    s.parent = this.current.parent;
 | 
					    s.parent = this.current.parent;
 | 
				
			||||||
 | 
					    s['x-index'] = newOrder;
 | 
				
			||||||
    this.current.parent.setProperties(properties);
 | 
					    this.current.parent.setProperties(properties);
 | 
				
			||||||
    this.emit('afterInsertAdjacent', 'afterEnd', s);
 | 
					    this.emit('afterInsertAdjacent', 'afterEnd', s, opts);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -297,7 +340,16 @@ export function useDesignable() {
 | 
				
			|||||||
  const field = useField();
 | 
					  const field = useField();
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
  const dn = createDesignable({ current: fieldSchema });
 | 
					  const dn = createDesignable({ current: fieldSchema });
 | 
				
			||||||
  dn.on('afterInsertAdjacent', refresh);
 | 
					  const api = useAPIClient();
 | 
				
			||||||
 | 
					  dn.on('afterInsertAdjacent', async (current, position, schema) => {
 | 
				
			||||||
 | 
					    refresh();
 | 
				
			||||||
 | 
					    // await api.request({
 | 
				
			||||||
 | 
					    //   url: `/ui_schemas:insertAdjacent/${current['x-uid']}?position=${position}`,
 | 
				
			||||||
 | 
					    //   method: 'post',
 | 
				
			||||||
 | 
					    //   data: schema.toJSON(),
 | 
				
			||||||
 | 
					    // });
 | 
				
			||||||
 | 
					    // console.log(current, position, schema);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
  dn.on('afterRemove', refresh);
 | 
					  dn.on('afterRemove', refresh);
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    designable,
 | 
					    designable,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user