feat: improve code

This commit is contained in:
chenos 2022-02-20 13:09:33 +08:00
parent 351bb88245
commit 257488ebad
19 changed files with 262 additions and 128 deletions

View File

@ -1,31 +1,11 @@
import { observer, useField, useFieldSchema } from '@formily/react';
import React, { useState } from 'react';
import { observer } from '@formily/react';
import React from 'react';
import { Link } from 'react-router-dom';
import { ActionContext } from './context';
import { useA } from './hooks';
import Action from './Action';
import { ComposedAction } from './types';
export const ActionLink: ComposedAction = observer((props: any) => {
const { openMode, containerRefKey, useAction = useA, onClick, ...others } = props;
const [visible, setVisible] = useState(false);
const schema = useFieldSchema();
const field = useField();
const { run } = useAction();
return (
<ActionContext.Provider value={{ visible, setVisible, openMode, containerRefKey }}>
<Link
{...others}
onClick={(e) => {
onClick && onClick(e);
setVisible(true);
run();
}}
>
{field.title}
</Link>
{props.children}
</ActionContext.Provider>
);
return <Action {...props} component={Link} className={'nb-action-link'}/>;
});
export default ActionLink;

View File

@ -1,39 +1,110 @@
import { observer, useField, useFieldSchema } from '@formily/react';
import { css } from '@emotion/css';
import { observer, useField } from '@formily/react';
import { Button } from 'antd';
import classnames from 'classnames';
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
import { SortableItem } from '../../common';
import { useDesigner } from '../../hooks';
import ActionContainer from './Action.Container';
import { ActionDrawer } from './Action.Drawer';
import { ActionLink } from './Action.Link';
import { ActionModal } from './Action.Modal';
import { ActionPage } from './Action.Page';
import { ActionContext } from './context';
import { useA } from './hooks';
import { ComposedAction } from './types';
export const actionDesignerCss = css`
position: relative;
&:hover {
> .general-schema-designer {
display: block;
}
}
&.nb-action-link {
> .general-schema-designer {
top: -10px;
bottom: -10px;
left: -10px;
right: -10px;
}
}
> .general-schema-designer {
position: absolute;
z-index: 999;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: none;
background: rgba(241, 139, 98, 0.06);
border: 0;
top: 0;
bottom: 0;
left: 0;
right: 0;
pointer-events: none;
> .general-schema-designer-icons {
position: absolute;
right: 2px;
top: 2px;
line-height: 16px;
pointer-events: all;
.ant-space-item {
background-color: #f18b62;
color: #fff;
line-height: 16px;
width: 16px;
padding-left: 1px;
}
}
}
`;
export const Action: ComposedAction = observer((props: any) => {
const { openMode, containerRefKey, useAction = useA, onClick, ...others } = props;
const { openMode, containerRefKey, component, useAction = useA, onClick, className, ...others } = props;
const [visible, setVisible] = useState(false);
const schema = useFieldSchema();
const Designer = useDesigner();
const field = useField();
const { run } = useAction();
return (
<ActionContext.Provider value={{ visible, setVisible, openMode, containerRefKey }}>
<Button
<SortableItem
{...others}
onClick={(e) => {
onClick && onClick(e);
setVisible(true);
run();
}}
component={component || Button}
className={classnames(className, actionDesignerCss)}
>
<Designer />
{field.title}
</Button>
</SortableItem>
{props.children}
</ActionContext.Provider>
);
});
Action.Link = ActionLink;
Action.Designer = () => {
return (
<GeneralSchemaDesigner>
<SchemaSettings.Remove
removeParentsIfNoChildren
breakRemoveOn={(s) => {
return s['x-component'] === 'Space' || s['x-component'] === 'ActionBar';
}}
/>
</GeneralSchemaDesigner>
);
};
Action.Link = observer((props) => {
return <Action {...props} component={Link} className={'nb-action-link'}/>;
});
Action.Drawer = ActionDrawer;
Action.Modal = ActionModal;
Action.Container = ActionContainer;

View File

@ -1,6 +1,7 @@
import { ButtonProps, DrawerProps } from 'antd';
export type ActionProps = ButtonProps & {
component?: any;
useAction?: () => {
run(): Promise<void>;
};

View File

@ -62,6 +62,7 @@ export const ArrayTable: ArrayTableType = observer((props) => {
ArrayTable.Column = (props) => {
const field = useField();
console.log('field.title', field.title);
return <div>{field.title}</div>;
};

View File

@ -1,41 +0,0 @@
import { observer, useFieldSchema } from '@formily/react';
import React from 'react';
import { createDesignable, useDesignable } from '../..';
import { useAPIClient } from '../../../api-client';
export const TableActionDesignable = observer((props) => {
const fieldSchema = useFieldSchema();
const api = useAPIClient();
const { refresh } = useDesignable();
return (
<div>
<span
onClick={() => {
const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
if (schema['x-component'] === 'Space') {
return schema;
}
return buf;
}, null);
const dn = createDesignable({
current: spaceSchema,
refresh,
api,
});
dn.loadAPIClientEvents();
dn.insertBeforeEnd({
type: 'void',
title: '{{ t("Delete") }}',
'x-component': 'Action.Link',
'x-component-props': {
useAction: '{{ useDestroyAction }}',
},
});
}}
>
Edit
</span>
{props.children}
</div>
);
});

View File

@ -1,4 +0,0 @@
import React from 'react';
export const TableActionDesignableBar = () => {
return <div>Edit</div>;
};

View File

@ -1,14 +1,53 @@
import { observer, useFieldSchema } from '@formily/react';
import { css } from '@emotion/css';
import { observer } from '@formily/react';
import React from 'react';
import { useComponent } from '../..';
import { SortableItem, useDesigner } from '../..';
export const designerCss = css`
position: relative;
&:hover {
> .general-schema-designer {
display: block;
}
}
> .general-schema-designer {
position: absolute;
z-index: 999;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: none;
background: rgba(241, 139, 98, 0.06) !important;
border: 0 !important;
top: -16px !important;
bottom: -16px !important;
left: -16px !important;
right: -16px !important;
pointer-events: none;
> .general-schema-designer-icons {
position: absolute;
right: 2px;
top: 2px;
line-height: 16px;
pointer-events: all;
.ant-space-item {
background-color: #f18b62;
color: #fff;
line-height: 16px;
width: 16px;
padding-left: 1px;
}
}
}
`;
export const TableColumnActionBar = observer((props) => {
const fieldSchema = useFieldSchema();
const ActionInitializer = useComponent(fieldSchema['x-action-initializer']);
const Designer = useDesigner();
return (
<div>
{ActionInitializer && <ActionInitializer />}
<SortableItem className={designerCss}>
<Designer />
{props.children}
</div>
</SortableItem>
);
});

View File

@ -1,7 +1,6 @@
import { useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import React, { useEffect } from 'react';
import { useCollection, useDesignable } from '../../../';
import React, { useLayoutEffect } from 'react';
import { designerCss, SortableItem, useCollection, useDesignable, useDesigner } from '../../../';
export const useColumnSchema = () => {
const { getField } = useCollection();
@ -20,10 +19,11 @@ export const useColumnSchema = () => {
};
export const TableColumnDecorator = (props) => {
const Designer = useDesigner();
const field = useField();
const { columnSchema, fieldSchema, collectionField } = useColumnSchema();
const { refresh } = useDesignable();
useEffect(() => {
useLayoutEffect(() => {
if (field.title) {
return;
}
@ -33,22 +33,25 @@ export const TableColumnDecorator = (props) => {
if (collectionField?.uiSchema?.title) {
field.title = collectionField?.uiSchema?.title;
}
}, []);
}, [collectionField?.uiSchema?.title]);
console.log('field.title', collectionField?.uiSchema?.title, field.title);
return (
<>
{props.children}
<div
<SortableItem className={designerCss}>
<Designer />
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
{field.title || collectionField?.uiSchema?.title}
{/* <div
onClick={() => {
field.title = uid();
columnSchema.title = field.title = field.title;
refresh();
field.query(`.*.${fieldSchema.name}`).take((f) => {
f.componentProps.dateFormat = 'YYYY-MM-DD';
});
// columnSchema.title = field.title = field.title;
// refresh();
// field.query(`.*.${fieldSchema.name}`).take((f) => {
// f.componentProps.dateFormat = 'YYYY-MM-DD';
// });
}}
>
Edit
</div>
</>
</div> */}
</SortableItem>
);
};

View File

@ -0,0 +1,35 @@
import { useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import React from 'react';
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
import { useDesignable } from '../../hooks';
export const TableColumnDeigner = () => {
const field = useField();
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
return (
<GeneralSchemaDesigner>
<SchemaSettings.Item
title={'编辑'}
onClick={() => {
field.title = uid();
fieldSchema.title = uid();
dn.emit('patch', {
schema: {
'x-uid': fieldSchema['x-uid'],
title: fieldSchema.title,
},
});
}}
/>
<SchemaSettings.Divider />
<SchemaSettings.Remove
removeParentsIfNoChildren
breakRemoveOn={{
'x-component': 'Grid',
}}
/>
</GeneralSchemaDesigner>
);
};

View File

@ -0,0 +1,22 @@
import { DragOutlined } from '@ant-design/icons';
import { useFieldSchema } from '@formily/react';
import { Space } from 'antd';
import React from 'react';
import { DragHandler, useComponent } from '../../../schema-component';
export const TableRecordActionDesigner = (props: any) => {
const fieldSchema = useFieldSchema();
const ActionInitializer = useComponent(fieldSchema['x-action-initializer']);
return (
<div className={'general-schema-designer'}>
<div className={'general-schema-designer-icons'}>
<Space size={2} align={'center'}>
<DragHandler>
<DragOutlined />
</DragHandler>
<ActionInitializer />
</Space>
</div>
</div>
);
};

View File

@ -1,5 +1,6 @@
export * from './ArrayTable';
export * from './TableColumnActionBar';
export * from './TableColumnDecorator';
export * from './TableColumnDeigner';
export * from './TableRecordActionDesigner';

View File

@ -19,7 +19,7 @@ export const BlockItem: React.FC<any> = (props) => {
}
}
&.nb-form-item:hover {
.general-schema-designer {
> .general-schema-designer {
background: rgba(241, 139, 98, 0.06) !important;
border: 0 !important;
top: -5px !important;
@ -28,7 +28,7 @@ export const BlockItem: React.FC<any> = (props) => {
right: -5px !important;
}
}
.general-schema-designer {
> .general-schema-designer {
position: absolute;
z-index: 999;
top: 0;
@ -38,7 +38,7 @@ export const BlockItem: React.FC<any> = (props) => {
display: none;
border: 2px solid rgba(241, 139, 98, 0.3);
pointer-events: none;
.general-schema-designer-icons {
> .general-schema-designer-icons {
position: absolute;
right: 2px;
top: 2px;

View File

@ -3,46 +3,51 @@ import { observer, useField, useFieldSchema } from '@formily/react';
import React, { createContext, useContext } from 'react';
export const DraggableContext = createContext(null);
export const SortableContext = createContext(null);
export const Sortable = (props: any) => {
const { id, data, style, children, ...others } = props;
export const SortableProvider = (props) => {
const { id, data, children } = props;
const draggable = useDraggable({
id,
data,
});
const { isOver, setNodeRef } = useDroppable({
const droppable = useDroppable({
id,
data,
});
return <SortableContext.Provider value={{ draggable, droppable }}>{children}</SortableContext.Provider>;
};
export const Sortable = (props: any) => {
const { component, style, children, ...others } = props;
const { droppable } = useContext(SortableContext);
const { isOver, setNodeRef } = droppable;
const droppableStyle = { ...style };
if (isOver) {
droppableStyle['color'] = 'rgba(241, 139, 98, .1)';
}
return (
<DraggableContext.Provider value={draggable}>
<div {...others} ref={setNodeRef} style={droppableStyle}>
{children}
</div>
</DraggableContext.Provider>
);
return React.createElement(component || 'div', {
...others,
ref: setNodeRef,
style: droppableStyle,
}, children);
};
export const SortableItem: React.FC<any> = observer((props) => {
const field = useField();
const fieldSchema = useFieldSchema();
return (
<Sortable {...props} id={field.address.toString()} data={{ insertAdjacent: 'afterEnd', schema: fieldSchema }}>
{props.children}
</Sortable>
<SortableProvider id={field.address.toString()} data={{ insertAdjacent: 'afterEnd', schema: fieldSchema }}>
<Sortable {...props}>{props.children}</Sortable>
</SortableProvider>
);
});
export const DragHandler = (props) => {
const { isDragging, attributes, listeners, setNodeRef, transform } = useContext(DraggableContext);
const { draggable } = useContext(SortableContext);
const { isDragging, attributes, listeners, setNodeRef, transform } = draggable;
const style = transform
? {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,

View File

@ -51,10 +51,10 @@ const createSchema = (collectionName) => {
properties: {
actions: {
type: 'void',
title: 'Actions',
'x-designer': 'TestDesigner',
title: '{{ t("Actions") }}',
'x-decorator': 'TableColumnActionBar',
'x-component': 'VoidTable.Column',
'x-designer': 'TableRecordActionDesigner',
'x-action-initializer': 'TableRecordActionInitializer',
properties: {
actions: {

View File

@ -34,7 +34,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
}
insert({
type: 'void',
'x-designer': 'TestDesigner',
'x-designer': 'Action.Designer',
'x-component': 'Action',
...item.schema,
});

View File

@ -16,7 +16,6 @@ const useTableColumnInitializerFields = () => {
title: field?.uiSchema?.title || field.name,
schema: {
name: field.name,
'x-designer': 'TestDesigner',
'x-collection-field': `${name}.${field.name}`,
'x-component': 'CollectionField',
},
@ -63,6 +62,7 @@ const ColumnInitializerItem = SchemaInitializer.itemWrap((props) => {
insert({
type: 'void',
'x-decorator': 'TableColumnDecorator',
'x-designer': 'TableColumnDeigner',
'x-component': 'VoidTable.Column',
properties: {
[item.schema.name]: {

View File

@ -1,3 +1,5 @@
import { MenuOutlined } from '@ant-design/icons';
import { css } from '@emotion/css';
import { observer, Schema, useFieldSchema } from '@formily/react';
import { Switch } from 'antd';
import React from 'react';
@ -67,7 +69,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
}
insert({
type: 'void',
'x-designer': 'TestDesigner',
'x-designer': 'Action.Designer',
'x-component': 'Action.Link',
...item.schema,
});
@ -87,6 +89,16 @@ export const TableRecordActionInitializer = observer((props: any) => {
const { t } = useTranslation();
return (
<SchemaInitializer.Button
className={css`
border: 0 !important;
color: #fff !important;
background: none !important;
height: auto !important;
line-height: 12px !important;
width: 12px !important;
padding: 0;
font-size: 12px;
`}
insertPosition={'beforeEnd'}
insert={(schema) => {
const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
@ -119,6 +131,7 @@ export const TableRecordActionInitializer = observer((props: any) => {
title: '{{ t("View") }}',
type: 'void',
'x-action': 'view',
'x-designer': 'Action.Designer',
'x-component': 'Action.Link',
'x-component-props': {},
properties: {
@ -231,7 +244,7 @@ export const TableRecordActionInitializer = observer((props: any) => {
},
]}
>
Configure
<MenuOutlined />
</SchemaInitializer.Button>
);
});

View File

@ -16,7 +16,7 @@ export const SchemaInitializerItemContext = createContext(null);
export const SchemaInitializer = () => null;
SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
const { insert, wrap = defaultWrap, items = [], insertPosition, dropdown, ...others } = props;
const { insert, wrap = defaultWrap, items = [], insertPosition, dropdown, style, ...others } = props;
let { insertAdjacent, findComponent } = useDesignable();
const [visible, setVisible] = useState(false);
const insertSchema = (schema) => {
@ -96,6 +96,7 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
{...others}
type={'dashed'}
style={{
...style,
borderColor: '#f18b62',
color: '#f18b62',
}}

View File

@ -65,7 +65,15 @@ export const SchemaSettings: React.FC<SchemaSettingsProps> & SchemaSettingsNeste
SchemaSettings.Item = (props) => {
return (
<Menu.Item {...props} style={{ minWidth: 120 }}>
<Menu.Item
{...props}
onClick={(info) => {
info.domEvent.preventDefault();
info.domEvent.stopPropagation();
props?.onClick?.(info);
}}
style={{ minWidth: 120 }}
>
{props.children || props.title}
</Menu.Item>
);
@ -87,8 +95,7 @@ SchemaSettings.Remove = (props: any) => {
const { removeParentsIfNoChildren, breakRemoveOn } = props;
const { dn } = useSchemaSettings();
return (
<Menu.Item
style={{ minWidth: 120 }}
<SchemaSettings.Item
onClick={() => {
dn.remove(null, {
removeParentsIfNoChildren,
@ -97,7 +104,7 @@ SchemaSettings.Remove = (props: any) => {
}}
>
</Menu.Item>
</SchemaSettings.Item>
);
};