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>;
 | 
			
		||||
  update?: (params?: ActionParams) => Promise<any>;
 | 
			
		||||
  destroy?: (params?: ActionParams) => Promise<any>;
 | 
			
		||||
  [key: string]: (params?: ActionParams) => Promise<any>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
@ -123,6 +213,11 @@ export const AddGridBlockItem = observer((props: any) => {
 | 
			
		||||
              title: 'Form',
 | 
			
		||||
              component: FormBlockInitializerItem,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: 'item',
 | 
			
		||||
              title: 'Test',
 | 
			
		||||
              component: TestInitializerItem,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ]}
 | 
			
		||||
 | 
			
		||||
@ -74,8 +74,10 @@ const useCurrentFieldSchema = (path: string) => {
 | 
			
		||||
    remove() {
 | 
			
		||||
      schema &&
 | 
			
		||||
        remove(schema, {
 | 
			
		||||
          breakComponent: 'Grid',
 | 
			
		||||
          removeEmptyParents: true,
 | 
			
		||||
          removeParentsIfNoChildren: 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 { uid } from '@formily/shared';
 | 
			
		||||
import { BlockItem, DragHandler, Grid, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
@ -13,87 +12,151 @@ const Block = observer((props) => {
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ Grid, Block, BlockItem }}>
 | 
			
		||||
      <SchemaComponent
 | 
			
		||||
        schema={{
 | 
			
		||||
const schema = {
 | 
			
		||||
  _isJSONSchemaObject: true,
 | 
			
		||||
  version: '2.0',
 | 
			
		||||
  type: 'void',
 | 
			
		||||
  name: 'grid1',
 | 
			
		||||
  'x-decorator': 'CardItem',
 | 
			
		||||
  'x-component': 'Grid',
 | 
			
		||||
          'x-uid': uid(),
 | 
			
		||||
  properties: {
 | 
			
		||||
    row1: {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
      'x-component': 'Grid.Row',
 | 
			
		||||
              'x-uid': uid(),
 | 
			
		||||
      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',
 | 
			
		||||
              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',
 | 
			
		||||
              'x-uid': uid(),
 | 
			
		||||
      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() {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ Grid, Block, BlockItem }}>
 | 
			
		||||
      <SchemaComponent schema={schema} />
 | 
			
		||||
    </SchemaComponentProvider>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,20 +1,44 @@
 | 
			
		||||
import { ISchema } from '@formily/react';
 | 
			
		||||
import { ISchema, observer, useFieldSchema } from '@formily/react';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
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 = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
  properties: {
 | 
			
		||||
    grid: {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
  name: 'grid1',
 | 
			
		||||
      'x-component': 'Grid',
 | 
			
		||||
      'x-item-initializer': 'Grid.AddBlockItem',
 | 
			
		||||
      'x-uid': uid(),
 | 
			
		||||
      properties: {},
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentProvider components={{ Grid, CardItem, Markdown, Form, VoidTable }}>
 | 
			
		||||
    <SchemaComponentProvider components={{ BlockItem, Block, Grid, CardItem, Markdown, Form, VoidTable }}>
 | 
			
		||||
      <SchemaComponent schema={schema} />
 | 
			
		||||
    </SchemaComponentProvider>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
@ -1 +1,3 @@
 | 
			
		||||
export * from './Block';
 | 
			
		||||
export * from './Grid';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@ const useDragEnd = () => {
 | 
			
		||||
  const { refresh } = useDesignable();
 | 
			
		||||
 | 
			
		||||
  return ({ active, over }: DragEndEvent) => {
 | 
			
		||||
    console.log({ active, over });
 | 
			
		||||
    const activeSchema = active?.data?.current?.schema;
 | 
			
		||||
    const overSchema = over?.data?.current?.schema;
 | 
			
		||||
    const insertAdjacent = over?.data?.current?.insertAdjacent;
 | 
			
		||||
@ -35,7 +34,7 @@ const useDragEnd = () => {
 | 
			
		||||
    if (insertAdjacent) {
 | 
			
		||||
      dn.insertAdjacent(insertAdjacent, activeSchema, {
 | 
			
		||||
        wrap: wrapSchema,
 | 
			
		||||
        removeEmptyParents: true,
 | 
			
		||||
        removeParentsIfNoChildren: true,
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -34,16 +34,11 @@ export const Sortable = (props: any) => {
 | 
			
		||||
export const SortableItem: React.FC<any> = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const onInsertAdjacent = ({ dn, orginDraggedParentSchema }) => {
 | 
			
		||||
    dn.removeIfChildrenEmpty(orginDraggedParentSchema, {
 | 
			
		||||
      removeEmptyParents: true,
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
    <Sortable
 | 
			
		||||
      {...props}
 | 
			
		||||
      id={field.address.toString()}
 | 
			
		||||
      data={{ insertAdjacent: 'afterEnd', onInsertAdjacent, schema: fieldSchema }}
 | 
			
		||||
      data={{ insertAdjacent: 'afterEnd', schema: fieldSchema }}
 | 
			
		||||
    >
 | 
			
		||||
      {props.children}
 | 
			
		||||
    </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 set from 'lodash/set';
 | 
			
		||||
import React, { useContext } from 'react';
 | 
			
		||||
import { useAPIClient } from '../../api-client';
 | 
			
		||||
import { SchemaComponentContext } from '../context';
 | 
			
		||||
 | 
			
		||||
interface CreateDesignableProps {
 | 
			
		||||
@ -20,12 +21,14 @@ type Position = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd';
 | 
			
		||||
 | 
			
		||||
interface InsertAdjacentOptions {
 | 
			
		||||
  wrap?: (s: ISchema) => ISchema;
 | 
			
		||||
  removeEmptyParents?: boolean;
 | 
			
		||||
  removeParentsIfNoChildren?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BreakFn = (s: ISchema) => boolean;
 | 
			
		||||
 | 
			
		||||
interface RemoveOptions {
 | 
			
		||||
  removeEmptyParents?: boolean;
 | 
			
		||||
  breakComponent?: string;
 | 
			
		||||
  removeParentsIfNoChildren?: boolean;
 | 
			
		||||
  breakSchema?: ISchema | BreakFn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const generateUid = (s: ISchema) => {
 | 
			
		||||
@ -76,7 +79,7 @@ export class Designable {
 | 
			
		||||
    if (!this.events[name]) {
 | 
			
		||||
      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 = {}) {
 | 
			
		||||
@ -92,17 +95,16 @@ export class Designable {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeIfChildrenEmpty(schema?: Schema) {
 | 
			
		||||
  removeIfNoChildren(schema?: Schema) {
 | 
			
		||||
    if (!schema) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    let s = schema;
 | 
			
		||||
    const count = Object.keys(s.properties || {}).length;
 | 
			
		||||
    console.log('removeIfChildrenEmpty', count, s.properties);
 | 
			
		||||
    if (count > 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    let removed;
 | 
			
		||||
    let removed: Schema;
 | 
			
		||||
    while (s.parent) {
 | 
			
		||||
      removed = s.parent.removeProperty(s.name);
 | 
			
		||||
      const count = Object.keys(s.parent.properties || {}).length;
 | 
			
		||||
@ -111,18 +113,42 @@ export class Designable {
 | 
			
		||||
      }
 | 
			
		||||
      s = s.parent;
 | 
			
		||||
    }
 | 
			
		||||
    return removed;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  remove(schema?: Schema, options: RemoveOptions = {}) {
 | 
			
		||||
    const { removeEmptyParents, breakComponent } = options;
 | 
			
		||||
    const { removeParentsIfNoChildren, breakSchema } = options;
 | 
			
		||||
    let s = schema || this.current;
 | 
			
		||||
    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) {
 | 
			
		||||
      removed = s.parent.removeProperty(s.name);
 | 
			
		||||
      if (!removeEmptyParents) {
 | 
			
		||||
      if (!removeParentsIfNoChildren) {
 | 
			
		||||
        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;
 | 
			
		||||
      }
 | 
			
		||||
      const count = Object.keys(s.parent.properties || {}).length;
 | 
			
		||||
@ -131,7 +157,7 @@ export class Designable {
 | 
			
		||||
      }
 | 
			
		||||
      s = s.parent;
 | 
			
		||||
    }
 | 
			
		||||
    this.emit('afterRemove', removed);
 | 
			
		||||
    this.emit('afterRemove', removed, options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  insertBeforeBeginOrAfterEnd(schema: ISchema, options: InsertAdjacentOptions = {}) {
 | 
			
		||||
@ -164,33 +190,38 @@ export class Designable {
 | 
			
		||||
    if (!Schema.isSchemaInstance(this.current)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
			
		||||
    const properties = {};
 | 
			
		||||
    let start = false;
 | 
			
		||||
 | 
			
		||||
    const opts = {};
 | 
			
		||||
    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
			
		||||
    if (Schema.isSchemaInstance(schema)) {
 | 
			
		||||
      schema.parent.removeProperty(schema.name);
 | 
			
		||||
      if (removeEmptyParents) {
 | 
			
		||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
			
		||||
      if (removeParentsIfNoChildren) {
 | 
			
		||||
        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const properties = {};
 | 
			
		||||
    let start = false;
 | 
			
		||||
    let order = 0;
 | 
			
		||||
    let newOrder = 0;
 | 
			
		||||
    this.current.parent.mapProperties((property, key) => {
 | 
			
		||||
      if (key === this.current.name) {
 | 
			
		||||
        newOrder = order;
 | 
			
		||||
        start = true;
 | 
			
		||||
        ++order;
 | 
			
		||||
      }
 | 
			
		||||
      property['x-index'] = order;
 | 
			
		||||
      ++order;
 | 
			
		||||
      if (start) {
 | 
			
		||||
        properties[key] = property;
 | 
			
		||||
        this.current.parent.removeProperty(key);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.prepareProperty(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;
 | 
			
		||||
    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)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
			
		||||
    const opts = {};
 | 
			
		||||
    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
			
		||||
    if (Schema.isSchemaInstance(schema)) {
 | 
			
		||||
      schema.parent.removeProperty(schema.name);
 | 
			
		||||
      if (removeEmptyParents) {
 | 
			
		||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
			
		||||
      if (removeParentsIfNoChildren) {
 | 
			
		||||
        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    const properties = {};
 | 
			
		||||
    this.current.mapProperties((schema, key) => {
 | 
			
		||||
      properties[key] = schema;
 | 
			
		||||
    let order = 1;
 | 
			
		||||
    this.current.mapProperties((s, key) => {
 | 
			
		||||
      s['x-index'] = order;
 | 
			
		||||
      ++order;
 | 
			
		||||
      properties[key] = s;
 | 
			
		||||
    });
 | 
			
		||||
    this.current.properties = {};
 | 
			
		||||
    this.prepareProperty(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;
 | 
			
		||||
    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)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
			
		||||
    const opts = {};
 | 
			
		||||
    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
			
		||||
    if (Schema.isSchemaInstance(schema)) {
 | 
			
		||||
      schema.parent.removeProperty(schema.name);
 | 
			
		||||
      if (removeEmptyParents) {
 | 
			
		||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
			
		||||
      if (removeParentsIfNoChildren) {
 | 
			
		||||
        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.prepareProperty(schema);
 | 
			
		||||
    const wrapped = wrap(schema);
 | 
			
		||||
    const s = this.current.addProperty(wrapped.name || uid(), wrapped);
 | 
			
		||||
    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)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const properties = {};
 | 
			
		||||
    let start = false;
 | 
			
		||||
    const { wrap = defaultWrap, removeEmptyParents } = options;
 | 
			
		||||
    const opts = {};
 | 
			
		||||
    const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
 | 
			
		||||
    if (Schema.isSchemaInstance(schema)) {
 | 
			
		||||
      schema.parent.removeProperty(schema.name);
 | 
			
		||||
      console.log('insertAfterEnd', removeEmptyParents);
 | 
			
		||||
      if (removeEmptyParents) {
 | 
			
		||||
        this.removeIfChildrenEmpty(schema.parent);
 | 
			
		||||
      if (removeParentsIfNoChildren) {
 | 
			
		||||
        opts['removed'] = this.removeIfNoChildren(schema.parent);
 | 
			
		||||
      }
 | 
			
		||||
      schema.parent = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let order = 0;
 | 
			
		||||
    let newOrder = 0;
 | 
			
		||||
    let start = false;
 | 
			
		||||
    const properties = {};
 | 
			
		||||
 | 
			
		||||
    this.current.parent.mapProperties((property, key) => {
 | 
			
		||||
      property['x-index'] = order;
 | 
			
		||||
      if (key === this.current.name) {
 | 
			
		||||
        ++order;
 | 
			
		||||
        newOrder = order;
 | 
			
		||||
        start = true;
 | 
			
		||||
      }
 | 
			
		||||
      ++order;
 | 
			
		||||
      if (start && key !== this.current.name) {
 | 
			
		||||
        properties[key] = property;
 | 
			
		||||
        this.current.parent.removeProperty(key);
 | 
			
		||||
@ -277,13 +321,12 @@ export class Designable {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.prepareProperty(schema);
 | 
			
		||||
 | 
			
		||||
    const wrapped = wrap(schema);
 | 
			
		||||
 | 
			
		||||
    const s = this.current.parent.addProperty(wrapped.name || uid(), wrapped);
 | 
			
		||||
    s.parent = this.current.parent;
 | 
			
		||||
    s['x-index'] = newOrder;
 | 
			
		||||
    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 fieldSchema = useFieldSchema();
 | 
			
		||||
  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);
 | 
			
		||||
  return {
 | 
			
		||||
    designable,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user