updates
This commit is contained in:
parent
e8399e167e
commit
8d298de6fe
@ -17,20 +17,46 @@ 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>();
|
||||
const location = useLocation();
|
||||
const sideMenuRef = useRef();
|
||||
const [activeKey, setActiveKey] = useState(match.params.name);
|
||||
const [,setPageTitle] = usePageTitleContext();
|
||||
const [, setPageTitle] = usePageTitleContext();
|
||||
const onSelect = (info) => {
|
||||
console.log('LayoutWithMenu', info);
|
||||
if (!info.schema) {
|
||||
@ -58,6 +84,7 @@ function LayoutWithMenu({ schema }) {
|
||||
}}
|
||||
/>
|
||||
<Database />
|
||||
<DesignableToggle />
|
||||
</Layout.Header>
|
||||
<Layout>
|
||||
<Layout.Sider
|
||||
@ -103,11 +130,13 @@ export function AdminLayout({ route }: any) {
|
||||
}
|
||||
|
||||
return (
|
||||
<CollectionContextProvider>
|
||||
<PageTitleContextProvider>
|
||||
<LayoutWithMenu schema={data} />
|
||||
</PageTitleContextProvider>
|
||||
</CollectionContextProvider>
|
||||
<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,67 +697,136 @@ AddNew.FormItem = observer((props: any) => {
|
||||
placement={'bottomCenter'}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.ItemGroup title={'选择已有字段'}>
|
||||
<Menu.Item
|
||||
style={{
|
||||
minWidth: 150,
|
||||
}}
|
||||
onClick={async () => {
|
||||
let data: ISchema = generateFormItemSchema('Markdown');
|
||||
if (schema['key']) {
|
||||
data['key'] = uid();
|
||||
}
|
||||
if (isGridBlock(schema)) {
|
||||
path.pop();
|
||||
path.pop();
|
||||
data = generateGridBlock(data);
|
||||
}
|
||||
if (data) {
|
||||
let s;
|
||||
if (defaultAction === 'insertAfter') {
|
||||
s = insertAfter(data, [...path]);
|
||||
} else {
|
||||
s = insertBefore(data, [...path]);
|
||||
<Menu.ItemGroup title={`选择「${collection.title}」里已有字段`}>
|
||||
{collection?.fields?.map((field) => (
|
||||
<Menu.Item
|
||||
key={field.key}
|
||||
onClick={async () => {
|
||||
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);
|
||||
}
|
||||
await createSchema(s);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<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
|
||||
</Menu.Item>
|
||||
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);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{field?.uiSchema?.title || '未命名'}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.ItemGroup>
|
||||
<Menu.Divider />
|
||||
<Menu.SubMenu title={'新增字段'}>
|
||||
<Menu.Item
|
||||
style={{
|
||||
minWidth: 150,
|
||||
}}
|
||||
>
|
||||
单行文本
|
||||
</Menu.Item>
|
||||
<Menu.Item>多行文本</Menu.Item>
|
||||
<Menu.Item>手机号</Menu.Item>
|
||||
<Menu.Item>数字</Menu.Item>
|
||||
<Menu.Item>说明文本</Menu.Item>
|
||||
<Menu.SubMenu title={'新建字段'}>
|
||||
{options.map((option) => (
|
||||
<Menu.ItemGroup title={option.label}>
|
||||
{option.children.map((item) => (
|
||||
<Menu.Item
|
||||
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.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,91 +66,105 @@ export const Form: any = observer((props: any) => {
|
||||
const scope = useContext(SchemaExpressionScopeContext);
|
||||
return (
|
||||
<FormProvider form={form}>
|
||||
{schema['x-decorator'] === 'Form' ? (
|
||||
<SchemaField
|
||||
scope={scope}
|
||||
schema={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
[schema.name]: {
|
||||
...schema.toJSON(),
|
||||
'x-path': path,
|
||||
// 避免死循环
|
||||
'x-decorator': 'Form.__Decorator',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FormLayout layout={'vertical'} {...others}>
|
||||
{/* @ts-ignore */}
|
||||
<FormContextProvider schema={schema} form={form}>
|
||||
{schema['x-decorator'] === 'Form' ? (
|
||||
<SchemaField
|
||||
scope={scope}
|
||||
schema={{
|
||||
type: 'object',
|
||||
properties: schema.properties,
|
||||
properties: {
|
||||
[schema.name]: {
|
||||
...schema.toJSON(),
|
||||
'x-path': path,
|
||||
// 避免死循环
|
||||
'x-decorator': 'Form.__Decorator',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</FormLayout>
|
||||
)}
|
||||
) : (
|
||||
<FormLayout layout={'vertical'} {...others}>
|
||||
<SchemaField
|
||||
scope={scope}
|
||||
schema={{
|
||||
type: 'object',
|
||||
properties: schema.properties,
|
||||
}}
|
||||
/>
|
||||
</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);
|
||||
}
|
||||
}}
|
||||
>
|
||||
删除当前区块
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MenuOutlined />
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</span>
|
||||
</div>
|
||||
<RecursionField
|
||||
name={name}
|
||||
schema={
|
||||
new Schema({
|
||||
'x-path': path,
|
||||
type: 'void',
|
||||
properties: {
|
||||
[field.name]: {
|
||||
...field.uiSchema,
|
||||
title,
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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