updates
This commit is contained in:
		
							parent
							
								
									e8399e167e
								
							
						
					
					
						commit
						8d298de6fe
					
				| @ -17,13 +17,39 @@ import { | ||||
|   useHistory, | ||||
|   Redirect, | ||||
| } from 'react-router-dom'; | ||||
| import { CollectionContextProvider, PageTitleContextProvider, SchemaRenderer, usePageTitleContext } from '../../schemas'; | ||||
| import { | ||||
|   CollectionContextProvider, | ||||
|   PageTitleContextProvider, | ||||
|   SchemaRenderer, | ||||
|   SwithDesignableContextProvider, | ||||
|   usePageTitleContext, | ||||
|   useSwithDesignableContext, | ||||
| } from '../../schemas'; | ||||
| import { useRequest } from 'ahooks'; | ||||
| import './style.less'; | ||||
| 
 | ||||
| import { uid } from '@formily/shared'; | ||||
| import { ISchema } from '@formily/react'; | ||||
| import Database from './datatable'; | ||||
| import { HighlightOutlined } from '@ant-design/icons'; | ||||
| import { useCookieState } from 'ahooks'; | ||||
| import cls from 'classnames'; | ||||
| 
 | ||||
| function DesignableToggle() { | ||||
|   const { designable, setDesignable } = useSwithDesignableContext(); | ||||
|   return ( | ||||
|     <Button | ||||
|       className={cls('nb-designable-toggle', { active: designable })} | ||||
|       type={'primary'} | ||||
|       style={{ height: 46, border: 0 }} | ||||
|       onClick={() => { | ||||
|         setDesignable(!designable); | ||||
|       }} | ||||
|     > | ||||
|       <HighlightOutlined /> | ||||
|     </Button> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function LayoutWithMenu({ schema }) { | ||||
|   const match = useRouteMatch<any>(); | ||||
| @ -58,6 +84,7 @@ function LayoutWithMenu({ schema }) { | ||||
|           }} | ||||
|         /> | ||||
|         <Database /> | ||||
|         <DesignableToggle /> | ||||
|       </Layout.Header> | ||||
|       <Layout> | ||||
|         <Layout.Sider | ||||
| @ -103,11 +130,13 @@ export function AdminLayout({ route }: any) { | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <SwithDesignableContextProvider> | ||||
|       <CollectionContextProvider> | ||||
|         <PageTitleContextProvider> | ||||
|           <LayoutWithMenu schema={data} /> | ||||
|         </PageTitleContextProvider> | ||||
|       </CollectionContextProvider> | ||||
|     </SwithDesignableContextProvider> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -47,3 +47,10 @@ | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .nb-designable-toggle { | ||||
|   background: none !important; | ||||
|   &.active { | ||||
|     background: #1890ff !important; | ||||
|   } | ||||
| } | ||||
| @ -19,7 +19,7 @@ import { useMemo } from 'react'; | ||||
| import { CodeOutlined } from '@ant-design/icons'; | ||||
| import Editor from '@monaco-editor/react'; | ||||
| 
 | ||||
| import { ArrayCollapse, ArrayTable, FormLayout } from '@formily/antd'; | ||||
| import { ArrayCollapse, ArrayTable, FormLayout, FormItem as FormilyFormItem } from '@formily/antd'; | ||||
| 
 | ||||
| import { Space, Card, Modal, Spin } from 'antd'; | ||||
| import { Action } from '../../schemas/action'; | ||||
| @ -50,6 +50,7 @@ import { CardItem } from '../../schemas/card-item'; | ||||
| import { DragAndDrop } from '../../schemas/drag-and-drop'; | ||||
| import { TreeSelect } from '../../schemas/tree-select'; | ||||
| import { Page } from '../../schemas/page'; | ||||
| import { useCollectionContext, useSwithDesignableContext } from '../../schemas'; | ||||
| 
 | ||||
| export const BlockContext = createContext({ dragRef: null }); | ||||
| 
 | ||||
| @ -74,6 +75,7 @@ export const SchemaField = createSchemaField({ | ||||
|     ArrayTable, | ||||
|     FormLayout, | ||||
|     TreeSelect, | ||||
|     FormilyFormItem, | ||||
| 
 | ||||
|     DragAndDrop, | ||||
| 
 | ||||
| @ -188,10 +190,12 @@ export function useSchemaComponent(component: string) { | ||||
| } | ||||
| 
 | ||||
| export function useDesignable(path?: any) { | ||||
|   const { designable } = useSwithDesignableContext(); | ||||
|   const { schema = new Schema({}), refresh } = useContext(DesignableContext); | ||||
|   const schemaPath = path || useSchemaPath(); | ||||
|   const fieldSchema = useFieldSchema(); | ||||
|   let currentSchema = | ||||
|   let current; | ||||
|   let currentSchema = current = | ||||
|     findPropertyByPath(schema, schemaPath) || ({} as Schema); | ||||
|   if (!currentSchema) { | ||||
|     currentSchema = fieldSchema; | ||||
| @ -204,6 +208,9 @@ export function useDesignable(path?: any) { | ||||
|   const DesignableBar = | ||||
|     get(options.components, currentSchema['x-designable-bar']) || (() => null); | ||||
|   return { | ||||
|     designable, | ||||
|     root: schema, | ||||
|     currentSchema: current, | ||||
|     DesignableBar, | ||||
|     schema: currentSchema, | ||||
|     refresh, | ||||
| @ -325,10 +332,14 @@ export function useDesignable(path?: any) { | ||||
|         } | ||||
|         s.parent.removeProperty(s.name); | ||||
|         removed.push(s); | ||||
|         if (s['x-component'] === 'Grid.Row') { | ||||
|           return; | ||||
|         } | ||||
|         if (Object.keys(s.parent.properties || {}).length === 0) { | ||||
|           remove(s.parent); | ||||
|         } | ||||
|       }; | ||||
|       console.log({ removed }) | ||||
|       remove(target); | ||||
|       refresh(); | ||||
|       return removed; | ||||
| @ -353,12 +364,12 @@ export function getSchemaPath(schema: Schema) { | ||||
|   const path = schema['x-path'] || [schema.name]; | ||||
|   let parent = schema.parent; | ||||
|   while (parent) { | ||||
|     if (!parent.name) { | ||||
|       break; | ||||
|     } | ||||
|     // if (!parent.name) {
 | ||||
|     //   break;
 | ||||
|     // }
 | ||||
|     if (parent['x-path']) { | ||||
|       path.unshift(...parent['x-path']); | ||||
|     } else { | ||||
|     } else if (parent.name) { | ||||
|       path.unshift(parent.name); | ||||
|     } | ||||
|     parent = parent.parent; | ||||
| @ -434,6 +445,7 @@ export interface SchemaRendererProps { | ||||
| } | ||||
| 
 | ||||
| export const SchemaRenderer = (props: SchemaRendererProps) => { | ||||
|   const { designable } = useSwithDesignableContext(); | ||||
|   const [, refresh] = useState(uid()); | ||||
|   const form = useMemo(() => props.form || createForm(), []); | ||||
|   const schema = useMemo(() => { | ||||
| @ -456,6 +468,10 @@ export const SchemaRenderer = (props: SchemaRendererProps) => { | ||||
|     } | ||||
|     return new Schema(s); | ||||
|   }, []); | ||||
|   // useEffect(() => {
 | ||||
|   //   refresh(uid());
 | ||||
|   // }, [designable]);
 | ||||
|   console.log({ designable }, 'designable') | ||||
|   const defaultRender = ({ schema }) => ( | ||||
|     <FormProvider form={form}> | ||||
|       <SchemaField | ||||
|  | ||||
| @ -19,6 +19,8 @@ const request = extend({ | ||||
|   timeout: 1000, | ||||
| }); | ||||
| 
 | ||||
| // console.log = () => {}
 | ||||
| 
 | ||||
| const RouteSwitch = createRouteSwitch({ | ||||
|   components: { | ||||
|     AdminLayout, | ||||
|  | ||||
| @ -30,7 +30,7 @@ export const Action: any = observer((props: any) => { | ||||
|   const isDropdownOrPopover = | ||||
|     child && | ||||
|     ['Action.Dropdown', 'Action.Popover'].includes(child['x-component']); | ||||
|   console.log({ DesignableBar, schema }); | ||||
|   // console.log({ DesignableBar, schema });
 | ||||
|   return ( | ||||
|     <VisibleContext.Provider value={[visible, setVisible]}> | ||||
|       {!isDropdownOrPopover && ( | ||||
|  | ||||
| @ -47,6 +47,7 @@ import { | ||||
|   DatabaseOutlined, | ||||
| } from '@ant-design/icons'; | ||||
| import { | ||||
|   createCollectionField, | ||||
|   createOrUpdateCollection, | ||||
|   createSchema, | ||||
|   request, | ||||
| @ -57,6 +58,9 @@ import { | ||||
| import { uid } from '@formily/shared'; | ||||
| import { useRequest } from 'ahooks'; | ||||
| import { SchemaField } from '../../components/schema-renderer'; | ||||
| import { useFormContext } from '../form'; | ||||
| import { cloneDeep } from 'lodash'; | ||||
| import { options } from '../database-field/interfaces'; | ||||
| 
 | ||||
| const generateGridBlock = (schema: ISchema) => { | ||||
|   const name = schema.name || uid(); | ||||
| @ -429,6 +433,9 @@ function generateCardItemSchema(component) { | ||||
|       name: uid(), | ||||
|       'x-decorator': 'CardItem', | ||||
|       'x-component': 'Form', | ||||
|       'x-component-props': { | ||||
|         showDefaultButtons: true, | ||||
|       }, | ||||
|       'x-designable-bar': 'Form.DesignableBar', | ||||
|       properties: { | ||||
|         [uid()]: { | ||||
| @ -491,9 +498,14 @@ AddNew.CardItem = observer((props: any) => { | ||||
|   const { ghost, defaultAction } = props; | ||||
|   const { schema, insertBefore, insertAfter, appendChild } = useDesignable(); | ||||
|   const path = useSchemaPath(); | ||||
|   const { data: collections = [], loading, run } = useRequest('collections:findAll', { | ||||
|     formatResult: (result) => result?.data, | ||||
|   }); | ||||
|   // const {
 | ||||
|   //   data: collections = [],
 | ||||
|   //   loading,
 | ||||
|   //   run,
 | ||||
|   // } = useRequest('collections:findAll', {
 | ||||
|   //   formatResult: (result) => result?.data,
 | ||||
|   // });
 | ||||
|   const { data: collections = [], loading, refresh } = useCollectionContext(); | ||||
|   console.log({ collections }); | ||||
|   return ( | ||||
|     <Dropdown | ||||
| @ -501,9 +513,6 @@ AddNew.CardItem = observer((props: any) => { | ||||
|         minWidth: 200, | ||||
|       }} | ||||
|       onVisibleChange={(visible) => { | ||||
|         if (visible) { | ||||
|           run(); | ||||
|         } | ||||
|         console.log('onVisibleChange', visible); | ||||
|       }} | ||||
|       placement={'bottomCenter'} | ||||
| @ -511,6 +520,7 @@ AddNew.CardItem = observer((props: any) => { | ||||
|         <Menu | ||||
|           onClick={async (info) => { | ||||
|             let data: ISchema; | ||||
|             let collectionName = null; | ||||
|             if (['addNewTable', 'addNewForm'].includes(info.key)) { | ||||
|               const values = await FormDialog(`新建数据表`, () => { | ||||
|                 return ( | ||||
| @ -525,13 +535,16 @@ AddNew.CardItem = observer((props: any) => { | ||||
|                 }, | ||||
|               }); | ||||
|               await createOrUpdateCollection(values); | ||||
|               refresh(); | ||||
|               data = generateCardItemSchema( | ||||
|                 info.key === 'addNewTable' ? 'Table' : 'Form', | ||||
|               ); | ||||
|               collectionName = values.name; | ||||
|             } else if (info.key !== 'Markdown') { | ||||
|               const keys = info.key.split('.'); | ||||
|               const component = keys.shift(); | ||||
|               const tableName = keys.join('.'); | ||||
|               collectionName = tableName; | ||||
|               data = generateCardItemSchema(component); | ||||
|               console.log('info.keyPath', component, tableName); | ||||
|             } else { | ||||
| @ -540,6 +553,10 @@ AddNew.CardItem = observer((props: any) => { | ||||
|             if (schema['key']) { | ||||
|               data['key'] = uid(); | ||||
|             } | ||||
|             if (collectionName) { | ||||
|               data['x-component-props'] = data['x-component-props'] || {}; | ||||
|               data['x-component-props']['collectionName'] = collectionName; | ||||
|             } | ||||
|             if (isGridBlock(schema)) { | ||||
|               path.pop(); | ||||
|               path.pop(); | ||||
| @ -669,8 +686,9 @@ AddNew.BlockItem = observer((props: any) => { | ||||
| 
 | ||||
| AddNew.FormItem = observer((props: any) => { | ||||
|   const { ghost, defaultAction } = props; | ||||
|   const { schema, insertBefore, insertAfter } = useDesignable(); | ||||
|   const { schema, insertBefore, insertAfter, appendChild } = useDesignable(); | ||||
|   const path = useSchemaPath(); | ||||
|   const { collection = {}, refresh } = useFormContext(); | ||||
|   return ( | ||||
|     <Dropdown | ||||
|       overlayStyle={{ | ||||
| @ -679,24 +697,33 @@ AddNew.FormItem = observer((props: any) => { | ||||
|       placement={'bottomCenter'} | ||||
|       overlay={ | ||||
|         <Menu> | ||||
|           <Menu.ItemGroup title={'选择已有字段'}> | ||||
|           <Menu.ItemGroup title={`选择「${collection.title}」里已有字段`}> | ||||
|             {collection?.fields?.map((field) => ( | ||||
|               <Menu.Item | ||||
|               style={{ | ||||
|                 minWidth: 150, | ||||
|               }} | ||||
|                 key={field.key} | ||||
|                 onClick={async () => { | ||||
|                 let data: ISchema = generateFormItemSchema('Markdown'); | ||||
|                 if (schema['key']) { | ||||
|                   data['key'] = uid(); | ||||
|                 } | ||||
|                   let data: ISchema = { | ||||
|                     key: uid(), | ||||
|                     type: 'void', | ||||
|                     'x-decorator': 'Form.Field.Item', | ||||
|                     'x-designable-bar': 'Form.Field.DesignableBar', | ||||
|                     'x-component': 'Form.Field', | ||||
|                     'x-component-props': { | ||||
|                       fieldName: field.name, | ||||
|                     }, | ||||
|                   }; | ||||
|                   if (isGridBlock(schema)) { | ||||
|                     path.pop(); | ||||
|                     path.pop(); | ||||
|                     data = generateGridBlock(data); | ||||
|                   } else if (isGrid(schema)) { | ||||
|                     data = generateGridBlock(data); | ||||
|                   } | ||||
|                   if (data) { | ||||
|                     let s; | ||||
|                   if (defaultAction === 'insertAfter') { | ||||
|                     if (isGrid(schema)) { | ||||
|                       s = appendChild(data, [...path]); | ||||
|                     } else if (defaultAction === 'insertAfter') { | ||||
|                       s = insertAfter(data, [...path]); | ||||
|                     } else { | ||||
|                       s = insertBefore(data, [...path]); | ||||
| @ -705,41 +732,101 @@ AddNew.FormItem = observer((props: any) => { | ||||
|                   } | ||||
|                 }} | ||||
|               > | ||||
|               <Checkbox /> 字段 1 | ||||
|             </Menu.Item> | ||||
|             <Menu.Item> | ||||
|               <Checkbox /> 字段2 | ||||
|             </Menu.Item> | ||||
|             <Menu.Item> | ||||
|               <Checkbox /> 字段3 | ||||
|             </Menu.Item> | ||||
|             <Menu.Item> | ||||
|               <Checkbox /> 字段4 | ||||
|             </Menu.Item> | ||||
|             <Menu.Item> | ||||
|               <Checkbox /> 字段5 | ||||
|             </Menu.Item> | ||||
|             <Menu.Item> | ||||
|               <Checkbox /> 字段6 | ||||
|             </Menu.Item> | ||||
|             <Menu.Item> | ||||
|               <Checkbox /> 字段7 | ||||
|                 {field?.uiSchema?.title || '未命名'} | ||||
|               </Menu.Item> | ||||
|             ))} | ||||
|           </Menu.ItemGroup> | ||||
|           <Menu.Divider /> | ||||
|           <Menu.SubMenu title={'新增字段'}> | ||||
|           <Menu.SubMenu title={'新建字段'}> | ||||
|             {options.map((option) => ( | ||||
|               <Menu.ItemGroup title={option.label}> | ||||
|                 {option.children.map((item) => ( | ||||
|                   <Menu.Item | ||||
|               style={{ | ||||
|                 minWidth: 150, | ||||
|                     style={{ minWidth: 150 }} | ||||
|                     key={item.name} | ||||
|                     onClick={async () => { | ||||
|                       const values = await FormDialog(`新增字段`, () => { | ||||
|                         return ( | ||||
|                           <FormLayout layout={'vertical'}> | ||||
|                             <SchemaField schema={item} /> | ||||
|                           </FormLayout> | ||||
|                         ); | ||||
|                       }).open({ | ||||
|                         initialValues: { | ||||
|                           ...item.default, | ||||
|                           key: uid(), | ||||
|                           name: `f_${uid()}`, | ||||
|                         }, | ||||
|                       }); | ||||
|                       await createCollectionField(collection.name, values); | ||||
|                       await refresh(); | ||||
|                       let data: ISchema = cloneDeep(values.uiSchema); | ||||
|                       data['name'] = values.name; | ||||
|                       data['referenceKey'] = data['key']; | ||||
|                       data['key'] = uid(); | ||||
|                       if (isGridBlock(schema)) { | ||||
|                         path.pop(); | ||||
|                         path.pop(); | ||||
|                         data = generateGridBlock(data); | ||||
|                       } else if (isGrid(schema)) { | ||||
|                         data = generateGridBlock(data); | ||||
|                       } | ||||
|                       if (data) { | ||||
|                         let s; | ||||
|                         if (isGrid(schema)) { | ||||
|                           s = appendChild(data, [...path]); | ||||
|                         } else if (defaultAction === 'insertAfter') { | ||||
|                           s = insertAfter(data, [...path]); | ||||
|                         } else { | ||||
|                           s = insertBefore(data, [...path]); | ||||
|                         } | ||||
|                         await createSchema(s); | ||||
|                       } | ||||
|                     }} | ||||
|                   > | ||||
|               单行文本 | ||||
|                     {item.title} | ||||
|                   </Menu.Item> | ||||
|             <Menu.Item>多行文本</Menu.Item> | ||||
|             <Menu.Item>手机号</Menu.Item> | ||||
|             <Menu.Item>数字</Menu.Item> | ||||
|             <Menu.Item>说明文本</Menu.Item> | ||||
|                 ))} | ||||
|               </Menu.ItemGroup> | ||||
|             ))} | ||||
|           </Menu.SubMenu> | ||||
|           <Menu.Divider /> | ||||
|           <Menu.Item | ||||
|             onClick={async () => { | ||||
|               let data: ISchema = { | ||||
|                 key: uid(), | ||||
|                 type: 'string', | ||||
|                 default: '这是一段演示文字', | ||||
|                 'x-designable-bar': 'Markdown.FormItemDesignableBar', | ||||
|                 'x-decorator': 'FormItem', | ||||
|                 'x-read-pretty': true, | ||||
|                 'x-component': 'Markdown', | ||||
|                 'x-component-props': { | ||||
|                   savedInSchema: true, | ||||
|                 }, | ||||
|               }; | ||||
|               if (isGridBlock(schema)) { | ||||
|                 path.pop(); | ||||
|                 path.pop(); | ||||
|                 data = generateGridBlock(data); | ||||
|               } else if (isGrid(schema)) { | ||||
|                 data = generateGridBlock(data); | ||||
|               } | ||||
|               if (data) { | ||||
|                 let s; | ||||
|                 if (isGrid(schema)) { | ||||
|                   s = appendChild(data, [...path]); | ||||
|                 } else if (defaultAction === 'insertAfter') { | ||||
|                   s = insertAfter(data, [...path]); | ||||
|                 } else { | ||||
|                   s = insertBefore(data, [...path]); | ||||
|                 } | ||||
|                 await createSchema(s); | ||||
|               } | ||||
|             }} | ||||
|           > | ||||
|             添加说明文字 | ||||
|           </Menu.Item> | ||||
|         </Menu> | ||||
|       } | ||||
|     > | ||||
|  | ||||
| @ -39,7 +39,7 @@ const DraggableBlock = (props) => { | ||||
|       <div | ||||
|         onMouseEnter={(e) => { | ||||
|           setActive(true); | ||||
|           console.log('e.onMouseEnter', new Date().toString()); | ||||
|           // console.log('e.onMouseEnter', new Date().toString());
 | ||||
|         }} | ||||
|         onMouseMove={(event) => { | ||||
|           let dropElement = document.elementFromPoint( | ||||
| @ -65,11 +65,11 @@ const DraggableBlock = (props) => { | ||||
|           if (dropIds.length > 0) { | ||||
|             setActive(dropIds[0] === schema.name); | ||||
|           } | ||||
|           console.log('e.onMouseMove', dropIds, schema.name); | ||||
|           // console.log('e.onMouseMove', dropIds, schema.name);
 | ||||
|         }} | ||||
|         onMouseLeave={(e) => { | ||||
|           setActive(false); | ||||
|           console.log('e.onMouseLeave', new Date().toString()); | ||||
|           // console.log('e.onMouseLeave', new Date().toString());
 | ||||
|         }} | ||||
|         ref={mergeRefs([previewRef, dropRef])} | ||||
|         className={cls('nb-grid-block', 'designable-form-item', { | ||||
|  | ||||
| @ -6,12 +6,15 @@ export const select: ISchema = { | ||||
|   title: '下拉选择', | ||||
|   group: 'choices', | ||||
|   default: { | ||||
|     interface: 'select', | ||||
|     dataType: 'string', | ||||
|     // name,
 | ||||
|     uiSchema: { | ||||
|       type: 'string', | ||||
|       // title,
 | ||||
|       'x-component': 'Select', | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-designable-bar': 'Markdown.DesignableBar', | ||||
|       enum: [], | ||||
|     } as ISchema, | ||||
|   }, | ||||
|  | ||||
| @ -6,12 +6,15 @@ export const string: ISchema = { | ||||
|   title: '单行文本', | ||||
|   group: 'basic', | ||||
|   default: { | ||||
|     interface: 'string', | ||||
|     dataType: 'string', | ||||
|     // name,
 | ||||
|     uiSchema: { | ||||
|       type: 'string', | ||||
|       // title,
 | ||||
|       'x-component': 'Input', | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-designable-bar': 'Input.DesignableBar', | ||||
|     } as ISchema, | ||||
|   }, | ||||
|   properties: { | ||||
|  | ||||
| @ -6,11 +6,14 @@ export const subTable: ISchema = { | ||||
|   title: '子表格', | ||||
|   group: 'relation', | ||||
|   default: { | ||||
|     interface: 'subTable', | ||||
|     // name,
 | ||||
|     uiSchema: { | ||||
|       type: 'string', | ||||
|       // title,
 | ||||
|       'x-component': 'Select', | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Table', | ||||
|       'x-designable-bar': 'Markdown.DesignableBar', | ||||
|       enum: [], | ||||
|     } as ISchema, | ||||
|   }, | ||||
|  | ||||
| @ -11,7 +11,9 @@ export const textarea: ISchema = { | ||||
|     uiSchema: { | ||||
|       type: 'string', | ||||
|       // title,
 | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Input.TextArea', | ||||
|       'x-designable-bar': 'Markdown.DesignableBar', | ||||
|     } as ISchema, | ||||
|   }, | ||||
|   properties: { | ||||
|  | ||||
							
								
								
									
										94
									
								
								packages/client/src/schemas/form/DesignableBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								packages/client/src/schemas/form/DesignableBar.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| import React, { useContext, useMemo, useRef, useState } from 'react'; | ||||
| import { createForm } from '@formily/core'; | ||||
| import { | ||||
|   SchemaOptionsContext, | ||||
|   Schema, | ||||
|   useFieldSchema, | ||||
|   observer, | ||||
|   SchemaExpressionScopeContext, | ||||
|   FormProvider, | ||||
|   ISchema, | ||||
|   useField, | ||||
|   useForm, | ||||
|   RecursionField, | ||||
| } from '@formily/react'; | ||||
| import { | ||||
|   useSchemaPath, | ||||
|   SchemaField, | ||||
|   useDesignable, | ||||
|   removeSchema, | ||||
|   useCollectionContext, | ||||
| } from '../'; | ||||
| import get from 'lodash/get'; | ||||
| import { Button, Dropdown, Menu, Space } from 'antd'; | ||||
| import { MenuOutlined, DragOutlined } from '@ant-design/icons'; | ||||
| import cls from 'classnames'; | ||||
| import { FormLayout } from '@formily/antd'; | ||||
| import './style.less'; | ||||
| import AddNew from '../add-new'; | ||||
| import { DraggableBlockContext } from '../../components/drag-and-drop'; | ||||
| import { isGridRowOrCol } from '../grid'; | ||||
| import constate from 'constate'; | ||||
| import { useEffect } from 'react'; | ||||
| import { uid } from '@formily/shared'; | ||||
| import { getSchemaPath } from '../../components/schema-renderer'; | ||||
| 
 | ||||
| export const DesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const { designable, schema, refresh, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
|         onClick={(e) => { | ||||
|           e.stopPropagation(); | ||||
|         }} | ||||
|         className={cls('designable-bar-actions', { active: visible })} | ||||
|       > | ||||
|         <Space size={'small'}> | ||||
|           <AddNew.CardItem defaultAction={'insertAfter'} ghost /> | ||||
|           {dragRef && <DragOutlined ref={dragRef} />} | ||||
|           <Dropdown | ||||
|             trigger={['click']} | ||||
|             visible={visible} | ||||
|             onVisibleChange={(visible) => { | ||||
|               setVisible(visible); | ||||
|             }} | ||||
|             overlay={ | ||||
|               <Menu> | ||||
|                 <Menu.Item | ||||
|                   key={'update'} | ||||
|                   onClick={() => { | ||||
|                     field.readPretty = true; | ||||
|                   }} | ||||
|                 > | ||||
|                   编辑表单配置 | ||||
|                 </Menu.Item> | ||||
|                 <Menu.Divider /> | ||||
|                 <Menu.Item | ||||
|                   key={'delete'} | ||||
|                   onClick={async () => { | ||||
|                     const removed = deepRemove(); | ||||
|                     // console.log({ removed })
 | ||||
|                     const last = removed.pop(); | ||||
|                     if (isGridRowOrCol(last)) { | ||||
|                       await removeSchema(last); | ||||
|                     } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前表单 | ||||
|                 </Menu.Item> | ||||
|               </Menu> | ||||
|             } | ||||
|           > | ||||
|             <MenuOutlined /> | ||||
|           </Dropdown> | ||||
|         </Space> | ||||
|       </span> | ||||
|     </div> | ||||
|   ); | ||||
| }); | ||||
							
								
								
									
										114
									
								
								packages/client/src/schemas/form/Field.DesignableBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								packages/client/src/schemas/form/Field.DesignableBar.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| import React, { useContext, useMemo, useRef, useState } from 'react'; | ||||
| import { createForm } from '@formily/core'; | ||||
| import { | ||||
|   SchemaOptionsContext, | ||||
|   Schema, | ||||
|   useFieldSchema, | ||||
|   observer, | ||||
|   SchemaExpressionScopeContext, | ||||
|   FormProvider, | ||||
|   ISchema, | ||||
|   useField, | ||||
|   useForm, | ||||
|   RecursionField, | ||||
| } from '@formily/react'; | ||||
| import { | ||||
|   useSchemaPath, | ||||
|   SchemaField, | ||||
|   useDesignable, | ||||
|   removeSchema, | ||||
|   useCollectionContext, | ||||
|   updateSchema, | ||||
| } from '../'; | ||||
| import get from 'lodash/get'; | ||||
| import { Button, Dropdown, Menu, Space } from 'antd'; | ||||
| import { MenuOutlined, DragOutlined } from '@ant-design/icons'; | ||||
| import cls from 'classnames'; | ||||
| import { FormLayout } from '@formily/antd'; | ||||
| import './style.less'; | ||||
| import AddNew from '../add-new'; | ||||
| import { DraggableBlockContext } from '../../components/drag-and-drop'; | ||||
| import { isGridRowOrCol } from '../grid'; | ||||
| import constate from 'constate'; | ||||
| import { useEffect } from 'react'; | ||||
| import { uid } from '@formily/shared'; | ||||
| import { getSchemaPath } from '../../components/schema-renderer'; | ||||
| import { FormFieldUIDContext } from '.'; | ||||
| 
 | ||||
| export const FieldDesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const fieldSchema = useFieldSchema(); | ||||
|   const { designable, schema, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
|   const fieldUid = useContext(FormFieldUIDContext); | ||||
|   const fieldName = schema['x-component-props']?.['fieldName']; | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
|         onClick={(e) => { | ||||
|           e.stopPropagation(); | ||||
|         }} | ||||
|         className={cls('designable-bar-actions', { active: visible })} | ||||
|       > | ||||
|         <Space size={'small'}> | ||||
|           <AddNew.CardItem defaultAction={'insertAfter'} ghost /> | ||||
|           {dragRef && <DragOutlined ref={dragRef} />} | ||||
|           <Dropdown | ||||
|             trigger={['click']} | ||||
|             visible={visible} | ||||
|             onVisibleChange={(visible) => { | ||||
|               setVisible(visible); | ||||
|             }} | ||||
|             overlay={ | ||||
|               <Menu> | ||||
|                 <Menu.Item | ||||
|                   key={'update'} | ||||
|                   onClick={async () => { | ||||
|                     const title = uid(); | ||||
|                     field | ||||
|                       .query(field.address.concat(fieldUid, fieldName)) | ||||
|                       .take((f) => { | ||||
|                         f.title = title; | ||||
|                       }); | ||||
|                     console.log( | ||||
|                       'fieldfieldfieldfieldfield', | ||||
|                       field.address.concat(fieldUid, fieldName).entire, | ||||
|                       schema, | ||||
|                     ); | ||||
|                     schema['title'] = title; | ||||
|                     await updateSchema({ | ||||
|                       key: schema['key'], | ||||
|                       title, | ||||
|                     }); | ||||
|                   }} | ||||
|                 > | ||||
|                   修改字段配置 | ||||
|                 </Menu.Item> | ||||
|                 <Menu.Divider /> | ||||
|                 <Menu.Item | ||||
|                   key={'delete'} | ||||
|                   onClick={async () => { | ||||
|                     const removed = deepRemove(); | ||||
|                     console.log({ schema, removed }); | ||||
|                     const last = removed.pop(); | ||||
|                     if (isGridRowOrCol(last)) { | ||||
|                       await removeSchema(last); | ||||
|                     } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前字段 | ||||
|                 </Menu.Item> | ||||
|               </Menu> | ||||
|             } | ||||
|           > | ||||
|             <MenuOutlined /> | ||||
|           </Dropdown> | ||||
|         </Space> | ||||
|       </span> | ||||
|     </div> | ||||
|   ); | ||||
| }); | ||||
| @ -20,6 +20,13 @@ group: | ||||
|   // 添加其他节点 | ||||
| </Form> | ||||
| 
 | ||||
| <Form> | ||||
|   // Form.Field 可用于覆盖字段原配置,但不修改原字段配置,新配置只作用于当前 Form | ||||
|   <Form.Field title={'自定义标题'}> | ||||
|     <Input title={'原标题'}> | ||||
|   </Form.Field> | ||||
| </Form> | ||||
| 
 | ||||
| // Form 用作 decorator 时只用于创建独立的作用域 | ||||
| <Table x-decorator={'Form'}/> | ||||
| </pre> | ||||
|  | ||||
| @ -9,10 +9,18 @@ import { | ||||
|   FormProvider, | ||||
|   ISchema, | ||||
|   useField, | ||||
|   useForm, | ||||
|   RecursionField, | ||||
| } from '@formily/react'; | ||||
| import { useSchemaPath, SchemaField, useDesignable, removeSchema } from '../'; | ||||
| import { | ||||
|   useSchemaPath, | ||||
|   SchemaField, | ||||
|   useDesignable, | ||||
|   removeSchema, | ||||
|   useCollectionContext, | ||||
| } from '../'; | ||||
| import get from 'lodash/get'; | ||||
| import { Dropdown, Menu, Space } from 'antd'; | ||||
| import { Button, Dropdown, Menu, Space } from 'antd'; | ||||
| import { MenuOutlined, DragOutlined } from '@ant-design/icons'; | ||||
| import cls from 'classnames'; | ||||
| import { FormLayout } from '@formily/antd'; | ||||
| @ -20,9 +28,34 @@ import './style.less'; | ||||
| import AddNew from '../add-new'; | ||||
| import { DraggableBlockContext } from '../../components/drag-and-drop'; | ||||
| import { isGridRowOrCol } from '../grid'; | ||||
| import constate from 'constate'; | ||||
| import { useEffect } from 'react'; | ||||
| import { uid } from '@formily/shared'; | ||||
| import { getSchemaPath } from '../../components/schema-renderer'; | ||||
| import { DesignableBar } from './DesignableBar'; | ||||
| import { FieldDesignableBar } from './Field.DesignableBar'; | ||||
| import { createContext } from 'react'; | ||||
| import { BlockItem } from '../block-item'; | ||||
| 
 | ||||
| const [FormContextProvider, useFormContext] = constate(({ schema, form }) => { | ||||
|   // const schema = useFieldSchema();
 | ||||
|   const collectionName = schema['x-component-props']?.['collectionName']; | ||||
|   const { data: collections = [], loading, refresh } = useCollectionContext(); | ||||
|   const collection = collectionName | ||||
|     ? collections.find((item) => item.name === collectionName) | ||||
|     : {}; | ||||
|   console.log({ collection }); | ||||
|   return { form, schema, collection, refresh }; | ||||
| }); | ||||
| 
 | ||||
| export { FormContextProvider, useFormContext }; | ||||
| 
 | ||||
| export const Form: any = observer((props: any) => { | ||||
|   const { useValues = () => ({}), ...others } = props; | ||||
|   const { | ||||
|     useValues = () => ({}), | ||||
|     showDefaultButtons = false, | ||||
|     ...others | ||||
|   } = props; | ||||
|   const initialValues = useValues(); | ||||
|   const form = useMemo(() => { | ||||
|     console.log('Form.useMemo', initialValues); | ||||
| @ -33,6 +66,8 @@ export const Form: any = observer((props: any) => { | ||||
|   const scope = useContext(SchemaExpressionScopeContext); | ||||
|   return ( | ||||
|     <FormProvider form={form}> | ||||
|       {/* @ts-ignore */} | ||||
|       <FormContextProvider schema={schema} form={form}> | ||||
|         {schema['x-decorator'] === 'Form' ? ( | ||||
|           <SchemaField | ||||
|             scope={scope} | ||||
| @ -59,65 +94,77 @@ export const Form: any = observer((props: any) => { | ||||
|             /> | ||||
|           </FormLayout> | ||||
|         )} | ||||
|         {showDefaultButtons && ( | ||||
|           <Space style={{ marginTop: 24 }}> | ||||
|             <Button | ||||
|               onClick={async () => { | ||||
|                 const values = await form.submit(); | ||||
|                 console.log({ values }); | ||||
|               }} | ||||
|               type={'primary'} | ||||
|             > | ||||
|               提交 | ||||
|             </Button> | ||||
|             <Button | ||||
|               onClick={async () => { | ||||
|                 await form.reset(); | ||||
|               }} | ||||
|             > | ||||
|               重置 | ||||
|             </Button> | ||||
|           </Space> | ||||
|         )} | ||||
|       </FormContextProvider> | ||||
|     </FormProvider> | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| Form.__Decorator = ({ children }) => children; | ||||
| export const FormFieldUIDContext = createContext(null); | ||||
| 
 | ||||
| Form.DesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const { schema, refresh, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
| Form.Field = observer((props: any) => { | ||||
|   const { fieldName } = props; | ||||
|   const { schema } = useDesignable(); | ||||
|   const path = getSchemaPath(schema); | ||||
|   console.log('getSchemaPath', path); | ||||
|   const { collection = {} } = useFormContext(); | ||||
|   if (!fieldName) { | ||||
|     return null; | ||||
|   } | ||||
|   const field = collection?.fields?.find((item) => item.name === fieldName); | ||||
|   if (!field) { | ||||
|     return null; | ||||
|   } | ||||
|   const name = useContext(FormFieldUIDContext); | ||||
|   const title = schema['title'] || field.uiSchema['title']; | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
|         onClick={(e) => { | ||||
|           e.stopPropagation(); | ||||
|         }} | ||||
|         className={cls('designable-bar-actions', { active: visible })} | ||||
|       > | ||||
|         <Space size={'small'}> | ||||
|           <AddNew.CardItem defaultAction={'insertAfter'} ghost /> | ||||
|           {dragRef && <DragOutlined ref={dragRef} />} | ||||
|           <Dropdown | ||||
|             trigger={['click']} | ||||
|             visible={visible} | ||||
|             onVisibleChange={(visible) => { | ||||
|               setVisible(visible); | ||||
|             }} | ||||
|             overlay={ | ||||
|               <Menu> | ||||
|                 <Menu.Item | ||||
|                   key={'update'} | ||||
|                   onClick={() => { | ||||
|                     field.readPretty = false; | ||||
|                   }} | ||||
|                 > | ||||
|                   编辑Markdown | ||||
|                 </Menu.Item> | ||||
|                 <Menu.Divider /> | ||||
|                 <Menu.Item | ||||
|                   key={'delete'} | ||||
|                   onClick={async () => { | ||||
|                     const removed = deepRemove(); | ||||
|                     // console.log({ removed })
 | ||||
|                     const last = removed.pop(); | ||||
|                     if (isGridRowOrCol(last)) { | ||||
|                       await removeSchema(last); | ||||
|     <RecursionField | ||||
|       name={name} | ||||
|       schema={ | ||||
|         new Schema({ | ||||
|           'x-path': path, | ||||
|           type: 'void', | ||||
|           properties: { | ||||
|             [field.name]: { | ||||
|               ...field.uiSchema, | ||||
|               title, | ||||
|               'x-decorator': 'FormilyFormItem', | ||||
|             }, | ||||
|           }, | ||||
|         }) | ||||
|       } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前区块 | ||||
|                 </Menu.Item> | ||||
|               </Menu> | ||||
|             } | ||||
|           > | ||||
|             <MenuOutlined /> | ||||
|           </Dropdown> | ||||
|         </Space> | ||||
|       </span> | ||||
|     </div> | ||||
|     /> | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| Form.Field.Item = observer((props) => { | ||||
|   const name = uid(); | ||||
|   return ( | ||||
|     <FormFieldUIDContext.Provider value={name}> | ||||
|       <BlockItem>{props.children}</BlockItem> | ||||
|     </FormFieldUIDContext.Provider> | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| Form.__Decorator = ({ children }) => children; | ||||
| Form.DesignableBar = DesignableBar; | ||||
| Form.Field.DesignableBar = FieldDesignableBar; | ||||
|  | ||||
| @ -89,6 +89,7 @@ export const Grid: any = observer((props: any) => { | ||||
|   // const schema = useFieldSchema();
 | ||||
|   const gridPath = useSchemaPath(); | ||||
|   const { | ||||
|     designable, | ||||
|     schema, | ||||
|     schema: designableSchema, | ||||
|     insertAfter, | ||||
| @ -166,7 +167,7 @@ export const Grid: any = observer((props: any) => { | ||||
|             </> | ||||
|           ); | ||||
|         })} | ||||
|         {AddNewComponent && <AddNewComponent />} | ||||
|         {designable && AddNewComponent && <AddNewComponent />} | ||||
|       </div> | ||||
|     </DragDropManagerProvider> | ||||
|   ); | ||||
| @ -187,7 +188,7 @@ Grid.Row = observer((props) => { | ||||
|     deepRemove, | ||||
|   } = useDesignable(); | ||||
|   const len = Object.keys(designableSchema.properties || {}).length; | ||||
|   console.log({ len, schema, designableSchema }); | ||||
|   // console.log({ len, schema, designableSchema });
 | ||||
|   return ( | ||||
|     <ColumnSizeContext.Provider value={len}> | ||||
|       <ColDivider | ||||
|  | ||||
| @ -6,7 +6,7 @@ import { createContext } from 'react'; | ||||
| 
 | ||||
| import { extend } from 'umi-request'; | ||||
| import { isVoidField } from '@formily/core'; | ||||
| import { useRequest } from 'ahooks'; | ||||
| import { useCookieState, useRequest } from 'ahooks'; | ||||
| 
 | ||||
| export * from '../components/schema-renderer'; | ||||
| 
 | ||||
| @ -14,19 +14,19 @@ export function mapReadPretty(component, readPrettyProps) { | ||||
|   return function (target) { | ||||
|     return observer( | ||||
|       (props) => { | ||||
|         const field = useField() | ||||
|         const field = useField(); | ||||
|         if (!isVoidField(field) && field?.pattern === 'readPretty') { | ||||
|           return React.createElement(component, { | ||||
|             ...readPrettyProps, | ||||
|             ...props, | ||||
|           }) | ||||
|           }); | ||||
|         } | ||||
|         return React.createElement(target, props) | ||||
|         return React.createElement(target, props); | ||||
|       }, | ||||
|       { | ||||
|         forwardRef: true, | ||||
|       } | ||||
|     ) | ||||
|       }, | ||||
|     ); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| @ -57,6 +57,13 @@ export async function createOrUpdateCollection(data: any) { | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export async function createCollectionField(collectionName: string, data: any) { | ||||
|   return await request(`collections/${collectionName}/fields:create`, { | ||||
|     method: 'post', | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export async function deleteCollection(name) { | ||||
|   await request('collections:destroy', { | ||||
|     method: 'post', | ||||
| @ -109,3 +116,16 @@ const [CollectionContextProvider, useCollectionContext] = constate(() => { | ||||
| }); | ||||
| 
 | ||||
| export { CollectionContextProvider, useCollectionContext }; | ||||
| 
 | ||||
| const [SwithDesignableContextProvider, useSwithDesignableContext] = constate(() => { | ||||
|   const [active, setActive] = useCookieState('useCookieDesignable'); | ||||
| 
 | ||||
|   return { | ||||
|     designable: active === 'true', | ||||
|     setDesignable(value) { | ||||
|       setActive(value ? 'true' : 'false'); | ||||
|     } | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| export { SwithDesignableContextProvider, useSwithDesignableContext }; | ||||
|  | ||||
| @ -1,10 +1,19 @@ | ||||
| import React from 'react' | ||||
| import { connect, mapProps, mapReadPretty } from '@formily/react' | ||||
| import { connect, mapProps, mapReadPretty, observer, useField, useFieldSchema } from '@formily/react' | ||||
| import { Input as AntdInput } from 'antd' | ||||
| import { InputProps, TextAreaProps } from 'antd/lib/input' | ||||
| import { LoadingOutlined } from '@ant-design/icons' | ||||
| import { Display } from '../display'; | ||||
| import { DesignableBar } from './DesignableBar'; | ||||
| import { Dropdown, Menu, Space } from 'antd'; | ||||
| import { LoadingOutlined, MenuOutlined, DragOutlined } from '@ant-design/icons'; | ||||
| import { getSchemaPath, useDesignable } from '../../components/schema-renderer'; | ||||
| import { useContext, useState } from 'react'; | ||||
| import AddNew from '../add-new'; | ||||
| import cls from 'classnames'; | ||||
| import { DraggableBlockContext } from '../../components/drag-and-drop'; | ||||
| import { uid } from '@formily/shared'; | ||||
| import { removeSchema, updateSchema } from '..'; | ||||
| import { isGridRowOrCol } from '../grid'; | ||||
| 
 | ||||
| type ComposedInput = React.FC<InputProps> & { | ||||
|   TextArea?: React.FC<TextAreaProps> | ||||
| @ -15,6 +24,7 @@ type ComposedInput = React.FC<InputProps> & { | ||||
| export const Input: ComposedInput = connect( | ||||
|   AntdInput, | ||||
|   mapProps((props, field) => { | ||||
|     console.log('fieldfieldfieldfieldfield', field.address.entire); | ||||
|     return { | ||||
|       ...props, | ||||
|       suffix: ( | ||||
| @ -31,8 +41,65 @@ export const Input: ComposedInput = connect( | ||||
|   mapReadPretty(Display.Input) | ||||
| ) | ||||
| 
 | ||||
| Input.DesignableBar = DesignableBar; | ||||
| Input.TextArea = connect(AntdInput.TextArea, mapReadPretty(Display.TextArea)) | ||||
| Input.URL = connect(AntdInput, mapReadPretty(Display.URL)) | ||||
| 
 | ||||
| Input.DesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const fieldSchema = useFieldSchema(); | ||||
|   const { root, currentSchema, schema, refresh, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
|         onClick={(e) => { | ||||
|           e.stopPropagation(); | ||||
|         }} | ||||
|         className={cls('designable-bar-actions', { active: visible })} | ||||
|       > | ||||
|         <Space size={'small'}> | ||||
|           <AddNew.CardItem defaultAction={'insertAfter'} ghost /> | ||||
|           {dragRef && <DragOutlined ref={dragRef} />} | ||||
|           <Dropdown | ||||
|             trigger={['click']} | ||||
|             visible={visible} | ||||
|             onVisibleChange={(visible) => { | ||||
|               setVisible(visible); | ||||
|             }} | ||||
|             overlay={ | ||||
|               <Menu> | ||||
|                 <Menu.Item | ||||
|                   key={'update'} | ||||
|                   onClick={() => { | ||||
|                     console.log({ root, currentSchema, schema, fieldSchema }, getSchemaPath(fieldSchema)); | ||||
|                   }} | ||||
|                 > | ||||
|                   修改 Input | ||||
|                 </Menu.Item> | ||||
|                 <Menu.Divider /> | ||||
|                 <Menu.Item | ||||
|                   key={'delete'} | ||||
|                   onClick={async () => { | ||||
|                     const removed = deepRemove(); | ||||
|                     // console.log({ removed })
 | ||||
|                     const last = removed.pop(); | ||||
|                     if (isGridRowOrCol(last)) { | ||||
|                       await removeSchema(last); | ||||
|                     } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前区块 | ||||
|                 </Menu.Item> | ||||
|               </Menu> | ||||
|             } | ||||
|           > | ||||
|             <MenuOutlined /> | ||||
|           </Dropdown> | ||||
|         </Space> | ||||
|       </span> | ||||
|     </div> | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| export default Input | ||||
|  | ||||
| @ -20,6 +20,7 @@ import { DraggableBlockContext } from '../../components/drag-and-drop'; | ||||
| import { uid } from '@formily/shared'; | ||||
| import { removeSchema, updateSchema } from '..'; | ||||
| import { isGridRowOrCol } from '../grid'; | ||||
| import './style.less'; | ||||
| 
 | ||||
| export const Markdown: any = connect( | ||||
|   (props) => { | ||||
| @ -67,7 +68,7 @@ export const Markdown: any = connect( | ||||
|     console.log('Markdown', props); | ||||
|     let text = props.value; | ||||
|     let value = ( | ||||
|       <div dangerouslySetInnerHTML={{ __html: micromark(text || '') }} /> | ||||
|       <div className={'nb-markdown'} dangerouslySetInnerHTML={{ __html: micromark(text || '') }} /> | ||||
|     ); | ||||
|     return <Display.TextArea {...props} text={text} value={value} />; | ||||
|   }), | ||||
| @ -75,9 +76,12 @@ export const Markdown: any = connect( | ||||
| 
 | ||||
| Markdown.DesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const { schema, refresh, deepRemove } = useDesignable(); | ||||
|   const { designable, schema, refresh, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
| @ -117,7 +121,67 @@ Markdown.DesignableBar = observer((props) => { | ||||
|                     } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前区块 | ||||
|                   删除当前文本 | ||||
|                 </Menu.Item> | ||||
|               </Menu> | ||||
|             } | ||||
|           > | ||||
|             <MenuOutlined /> | ||||
|           </Dropdown> | ||||
|         </Space> | ||||
|       </span> | ||||
|     </div> | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| Markdown.FormItemDesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const { designable, schema, refresh, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
|         onClick={(e) => { | ||||
|           e.stopPropagation(); | ||||
|         }} | ||||
|         className={cls('designable-bar-actions', { active: visible })} | ||||
|       > | ||||
|         <Space size={'small'}> | ||||
|           <AddNew.FormItem defaultAction={'insertAfter'} ghost /> | ||||
|           {dragRef && <DragOutlined ref={dragRef} />} | ||||
|           <Dropdown | ||||
|             trigger={['click']} | ||||
|             visible={visible} | ||||
|             onVisibleChange={(visible) => { | ||||
|               setVisible(visible); | ||||
|             }} | ||||
|             overlay={ | ||||
|               <Menu> | ||||
|                 <Menu.Item | ||||
|                   key={'update'} | ||||
|                   onClick={() => { | ||||
|                     field.readPretty = false; | ||||
|                   }} | ||||
|                 > | ||||
|                   修改文本内容 | ||||
|                 </Menu.Item> | ||||
|                 <Menu.Divider /> | ||||
|                 <Menu.Item | ||||
|                   key={'delete'} | ||||
|                   onClick={async () => { | ||||
|                     const removed = deepRemove(); | ||||
|                     // console.log({ removed })
 | ||||
|                     const last = removed.pop(); | ||||
|                     if (isGridRowOrCol(last)) { | ||||
|                       await removeSchema(last); | ||||
|                     } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前文本 | ||||
|                 </Menu.Item> | ||||
|               </Menu> | ||||
|             } | ||||
|  | ||||
							
								
								
									
										3
									
								
								packages/client/src/schemas/markdown/style.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/client/src/schemas/markdown/style.less
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| .nb-markdown > *:last-child { | ||||
|   margin-bottom: 0; | ||||
| } | ||||
| @ -97,7 +97,7 @@ const SideMenu = (props: any) => { | ||||
| 
 | ||||
| export const Menu: any = observer((props: any) => { | ||||
|   const { mode, onSelect, sideMenuRef, ...others } = props; | ||||
|   const { schema } = useDesignable(); | ||||
|   const { designable, schema } = useDesignable(); | ||||
|   const fieldSchema = useFieldSchema(); | ||||
|   console.log('Menu.schema', schema, fieldSchema); | ||||
|   const [selectedKey, setSelectedKey] = useState(null); | ||||
| @ -275,8 +275,10 @@ Menu.SubMenu = observer((props: any) => { | ||||
| }); | ||||
| 
 | ||||
| Menu.AddNew = observer((props: any) => { | ||||
|   const { appendChild } = useDesignable(props.path); | ||||
| 
 | ||||
|   const { designable, appendChild } = useDesignable(props.path); | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
|   const schemas = { | ||||
|     'Menu.Link': { | ||||
|       icon: <MenuOutlined />, | ||||
| @ -516,11 +518,15 @@ Menu.DesignableBar = (props) => { | ||||
| 
 | ||||
|   const field = useField(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { schema, remove, refresh, insertAfter, insertBefore, appendChild } = | ||||
|   const { designable, schema, remove, refresh, insertAfter, insertBefore, appendChild } = | ||||
|     useDesignable(); | ||||
|   const formConfig = schemas[schema['x-component']]; | ||||
|   const isSubMenu = schema['x-component'] === 'Menu.SubMenu'; | ||||
| 
 | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <div | ||||
|  | ||||
| @ -32,10 +32,11 @@ import { | ||||
|   SortableElement, | ||||
| } from 'react-sortable-hoc'; | ||||
| import cls from 'classnames'; | ||||
| import { getSchemaPath, useDesignable, useSchemaPath, VisibleContext } from '../'; | ||||
| import { getSchemaPath, removeSchema, useDesignable, useSchemaPath, VisibleContext } from '../'; | ||||
| import './style.less'; | ||||
| import { DraggableBlockContext } from '../../components/drag-and-drop'; | ||||
| import AddNew from '../add-new'; | ||||
| import { isGridRowOrCol } from '../grid'; | ||||
| 
 | ||||
| interface TableRowProps { | ||||
|   index: number; | ||||
| @ -446,7 +447,6 @@ function useDesignableBar() { | ||||
| Table.Column = observer((props) => { | ||||
|   const schema = useFieldSchema(); | ||||
|   const field = useField(); | ||||
|   console.log('Table.Column', schema, field.title); | ||||
|   const { DesignableBar } = useDesignableBar(); | ||||
|   return ( | ||||
|     <div className={'nb-table-column'}> | ||||
| @ -461,7 +461,6 @@ Table.Column.DesignableBar = () => { | ||||
|   // const fieldSchema = useFieldSchema();
 | ||||
|   const { schema, remove, refresh, insertAfter } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   console.log('Table.Column.DesignableBar', { schema }); | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
| @ -571,7 +570,7 @@ Table.Index = observer((props) => { | ||||
|   const schema = useFieldSchema(); | ||||
|   const field = useField<Formily.Core.Models.Field>(); | ||||
|   const path = useSchemaPath(); | ||||
|   return <div>#{index + 1}</div>; | ||||
|   return <div>{index + 1}</div>; | ||||
| }); | ||||
| 
 | ||||
| Table.Addition = observer((props: any) => { | ||||
| @ -605,7 +604,7 @@ Table.Action.DesignableBar = () => { | ||||
|   const path = useSchemaPath(); | ||||
|   const { schema, remove, refresh, insertAfter } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   console.log('Table.Action.DesignableBar', path, field.address.entire, { schema, field }); | ||||
|   // console.log('Table.Action.DesignableBar', path, field.address.entire, { schema, field });
 | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
| @ -638,9 +637,12 @@ Table.Action.DesignableBar = () => { | ||||
| 
 | ||||
| Table.DesignableBar = observer((props) => { | ||||
|   const field = useField(); | ||||
|   const { schema, refresh, deepRemove } = useDesignable(); | ||||
|   const { designable, schema, refresh, deepRemove } = useDesignable(); | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { dragRef } = useContext(DraggableBlockContext); | ||||
|   if (!designable) { | ||||
|     return null; | ||||
|   } | ||||
|   return ( | ||||
|     <div className={cls('designable-bar', { active: visible })}> | ||||
|       <span | ||||
| @ -671,8 +673,13 @@ Table.DesignableBar = observer((props) => { | ||||
|                 <Menu.Divider /> | ||||
|                 <Menu.Item | ||||
|                   key={'delete'} | ||||
|                   onClick={() => { | ||||
|                     deepRemove(); | ||||
|                   onClick={async () => { | ||||
|                     const removed = deepRemove(); | ||||
|                     // console.log({ removed })
 | ||||
|                     const last = removed.pop(); | ||||
|                     if (isGridRowOrCol(last)) { | ||||
|                       await removeSchema(last); | ||||
|                     } | ||||
|                   }} | ||||
|                 > | ||||
|                   删除当前区块 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user