improve drag and drop
This commit is contained in:
parent
57cc9e6081
commit
cf2d3fcdaf
@ -29,6 +29,7 @@
|
|||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"beautiful-react-hooks": "^0.35.0",
|
"beautiful-react-hooks": "^0.35.0",
|
||||||
"constate": "^3.3.0",
|
"constate": "^3.3.0",
|
||||||
|
"html-react-parser": "^1.2.7",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"monaco-editor": "^0.25.2",
|
"monaco-editor": "^0.25.2",
|
||||||
"react-dnd": "^14.0.2",
|
"react-dnd": "^14.0.2",
|
||||||
|
100
packages/client/src/components/Sortable/index.tsx
Normal file
100
packages/client/src/components/Sortable/index.tsx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
SortableContext,
|
||||||
|
useSortable,
|
||||||
|
horizontalListSortingStrategy,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
sortableKeyboardCoordinates,
|
||||||
|
} from '@dnd-kit/sortable';
|
||||||
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
|
import { Menu, Table, Tabs } from 'antd';
|
||||||
|
import { createContext } from 'react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { range } from 'lodash';
|
||||||
|
const RowSyntheticListenerMapContext = createContext(null);
|
||||||
|
const CellContext = createContext(null);
|
||||||
|
import cls from 'classnames';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DndContext,
|
||||||
|
DragOverlay,
|
||||||
|
closestCenter,
|
||||||
|
KeyboardSensor,
|
||||||
|
PointerSensor,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
useDraggable,
|
||||||
|
useDroppable,
|
||||||
|
} from '@dnd-kit/core';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
import { DragOutlined } from '@ant-design/icons';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
|
||||||
|
const Div = forwardRef<HTMLDivElement>((props, ref) => {
|
||||||
|
return <div ref={ref} {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface SortableItemProps {}
|
||||||
|
|
||||||
|
export const SortableItemContext = createContext<any>({});
|
||||||
|
|
||||||
|
export function DragHandle() {
|
||||||
|
return (
|
||||||
|
<SortableItemContext.Consumer>
|
||||||
|
{({ setDraggableNodeRef, attributes, listeners }) =>
|
||||||
|
setDraggableNodeRef && (
|
||||||
|
<DragOutlined
|
||||||
|
ref={setDraggableNodeRef}
|
||||||
|
{...attributes}
|
||||||
|
{...listeners}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</SortableItemContext.Consumer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableItem(props) {
|
||||||
|
const { id, data = {}, className, component, children, ...others } = props;
|
||||||
|
const previewRef = useRef<HTMLElement>();
|
||||||
|
const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
||||||
|
id: `droppable-${id}`,
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
previewRef,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
isDragging,
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef: setDraggableNodeRef,
|
||||||
|
transform,
|
||||||
|
} = useDraggable({
|
||||||
|
id: `draggable-${id}`,
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
previewRef,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const Component = component || Div;
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
{...others}
|
||||||
|
className={cls(className, `droppable-${id}`, {
|
||||||
|
isOver,
|
||||||
|
isDragging,
|
||||||
|
})}
|
||||||
|
ref={(el: HTMLElement) => {
|
||||||
|
previewRef.current = el;
|
||||||
|
setDroppableNodeRef(el);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SortableItemContext.Provider
|
||||||
|
value={{ setDraggableNodeRef, attributes, listeners }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SortableItemContext.Provider>
|
||||||
|
</Component>
|
||||||
|
);
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { Resource } from '../resource';
|
|||||||
|
|
||||||
export const useResource = (options: any = {}) => {
|
export const useResource = (options: any = {}) => {
|
||||||
const { collection } = useCollectionContext();
|
const { collection } = useCollectionContext();
|
||||||
const resource = Resource.make(collection.name);
|
const resource = Resource.make(collection?.name);
|
||||||
return {
|
return {
|
||||||
initialValues: {},
|
initialValues: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -272,60 +272,68 @@ import { SchemaRenderer } from '@nocobase/client';
|
|||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'dropdown1',
|
name: 'action1',
|
||||||
title: '下拉菜单',
|
title: '下拉菜单',
|
||||||
'x-component': 'Action.Dropdown',
|
'x-component': 'Action',
|
||||||
'x-designable-bar': 'Action.DesignableBar',
|
'x-designable-bar': 'Action.DesignableBar',
|
||||||
'x-component-props': {},
|
'x-component-props': {
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
item1: {
|
dropdown1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `操作1`,
|
'x-component': 'Action.Dropdown',
|
||||||
'x-designable-bar': 'Action.DesignableBar',
|
'x-component-props': {},
|
||||||
'x-component': 'Menu.Action',
|
|
||||||
properties: {
|
properties: {
|
||||||
modal1: {
|
item1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '对话框标题',
|
title: `操作1`,
|
||||||
'x-component': 'Action.Modal',
|
'x-designable-bar': 'Action.DesignableBar',
|
||||||
|
'x-component': 'Menu.Action',
|
||||||
properties: {
|
properties: {
|
||||||
input: {
|
modal1: {
|
||||||
type: 'string',
|
|
||||||
title: '输入框',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-designable-bar': 'Input.DesignableBar',
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
title: '对话框标题',
|
||||||
'x-component-props': {
|
'x-component': 'Action.Modal',
|
||||||
addNewComponent: 'AddNew.FormItem',
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
title: '输入框',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-designable-bar': 'Input.DesignableBar',
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-component-props': {
|
||||||
|
addNewComponent: 'AddNew.FormItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
item2: {
|
||||||
|
type: 'void',
|
||||||
|
title: `操作2`,
|
||||||
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
|
'x-component': 'Menu.Action',
|
||||||
|
properties: {
|
||||||
|
modal2: {
|
||||||
|
type: 'void',
|
||||||
|
title: '对话框标题',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
item2: {
|
|
||||||
type: 'void',
|
|
||||||
title: `操作2`,
|
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
|
||||||
'x-component': 'Menu.Action',
|
|
||||||
properties: {
|
|
||||||
modal2: {
|
|
||||||
type: 'void',
|
|
||||||
title: '对话框标题',
|
|
||||||
'x-component': 'Action.Modal',
|
|
||||||
properties: {
|
|
||||||
input: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,9 +20,11 @@ import cls from 'classnames';
|
|||||||
import { MenuOutlined } from '@ant-design/icons';
|
import { MenuOutlined } from '@ant-design/icons';
|
||||||
import { FormLayout } from '@formily/antd';
|
import { FormLayout } from '@formily/antd';
|
||||||
import IconPicker from '../../components/icon-picker';
|
import IconPicker from '../../components/icon-picker';
|
||||||
import { useSchemaComponent } from '../../components/schema-renderer';
|
import { getSchemaPath, useSchemaComponent } from '../../components/schema-renderer';
|
||||||
import { VisibleContext } from '../../context';
|
import { VisibleContext } from '../../context';
|
||||||
|
|
||||||
|
export const ButtonComponentContext = createContext(null);
|
||||||
|
|
||||||
export const Action: any = observer((props: any) => {
|
export const Action: any = observer((props: any) => {
|
||||||
const { useAction = useDefaultAction, icon, ...others } = props;
|
const { useAction = useDefaultAction, icon, ...others } = props;
|
||||||
const { run } = useAction();
|
const { run } = useAction();
|
||||||
@ -33,23 +35,26 @@ export const Action: any = observer((props: any) => {
|
|||||||
const isDropdownOrPopover =
|
const isDropdownOrPopover =
|
||||||
child &&
|
child &&
|
||||||
['Action.Dropdown', 'Action.Popover'].includes(child['x-component']);
|
['Action.Dropdown', 'Action.Popover'].includes(child['x-component']);
|
||||||
|
const button = (
|
||||||
|
<Button
|
||||||
|
{...others}
|
||||||
|
icon={<IconPicker type={icon} />}
|
||||||
|
onClick={async () => {
|
||||||
|
setVisible(true);
|
||||||
|
await run();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{schema.title}
|
||||||
|
<DesignableBar path={getSchemaPath(schema)}/>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<VisibleContext.Provider value={[visible, setVisible]}>
|
<ButtonComponentContext.Provider value={button}>
|
||||||
{!isDropdownOrPopover && (
|
<VisibleContext.Provider value={[visible, setVisible]}>
|
||||||
<Button
|
{!isDropdownOrPopover && button}
|
||||||
{...others}
|
<RecursionField schema={schema} onlyRenderProperties />
|
||||||
icon={<IconPicker type={icon} />}
|
</VisibleContext.Provider>
|
||||||
onClick={async () => {
|
</ButtonComponentContext.Provider>
|
||||||
setVisible(true);
|
|
||||||
await run();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{schema.title}
|
|
||||||
<DesignableBar />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<RecursionField schema={schema} onlyRenderProperties />
|
|
||||||
</VisibleContext.Provider>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -187,49 +192,29 @@ Action.Drawer = observer((props: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Action.Dropdown = observer((props: any) => {
|
Action.Dropdown = observer((props: any) => {
|
||||||
const { buttonProps = {}, ...others } = props;
|
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
let componentProps = {...buttonProps};
|
const button = useContext(ButtonComponentContext);
|
||||||
let title = schema.title;
|
|
||||||
if (schema.parent['x-component'] === 'Action') {
|
|
||||||
title = schema.parent.title;
|
|
||||||
componentProps = {...buttonProps, ...(schema.parent['x-component-props'] || {})}
|
|
||||||
}
|
|
||||||
const icon = componentProps['icon'];
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
{...others}
|
{...props}
|
||||||
overlay={
|
overlay={
|
||||||
<Menu>
|
<Menu>
|
||||||
<RecursionField schema={schema} onlyRenderProperties />
|
<RecursionField schema={schema} onlyRenderProperties />
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button
|
<span>{button}</span>
|
||||||
{...buttonProps}
|
|
||||||
{...componentProps}
|
|
||||||
icon={<IconPicker type={icon} />}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</Button>
|
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Action.Popover = observer((props) => {
|
Action.Popover = observer((props) => {
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const isFormDecorator = schema['x-decorator'] === 'Form';
|
const isFormDecorator = schema['x-decorator'] === 'Form';
|
||||||
const [visible, setVisible] = useContext(VisibleContext);
|
const [visible, setVisible] = useContext(VisibleContext);
|
||||||
console.log('Action.Popover', schema, fieldSchema);
|
const button = useContext(ButtonComponentContext);
|
||||||
const componentProps =
|
|
||||||
(schema.parent && schema.parent['x-component-props']) || {};
|
|
||||||
const designableBarComponent = schema.parent
|
|
||||||
? schema.parent['x-designable-bar']
|
|
||||||
: null;
|
|
||||||
const DesignableBar = useSchemaComponent(designableBarComponent);
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -266,18 +251,15 @@ Action.Popover = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button {...componentProps}>
|
{button}
|
||||||
{schema.parent.title || schema.title}
|
|
||||||
{DesignableBar && <DesignableBar />}
|
|
||||||
</Button>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Action.DesignableBar = () => {
|
Action.DesignableBar = (props: any) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
// const schema = useFieldSchema();
|
// const schema = useFieldSchema();
|
||||||
const { schema, insertAfter, refresh } = useDesignable();
|
const { schema, insertAfter, refresh } = useDesignable(props.path);
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
@ -297,7 +279,7 @@ Action.DesignableBar = () => {
|
|||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
// console.log({ field, schema });
|
console.log('按钮文案被修改了', { schema });
|
||||||
schema.title = '按钮文案被修改了';
|
schema.title = '按钮文案被修改了';
|
||||||
// field.setTitle('按钮文案被修改了');
|
// field.setTitle('按钮文案被修改了');
|
||||||
// setVisible(false);
|
// setVisible(false);
|
||||||
|
@ -109,7 +109,7 @@ const isGridBlock = (schema: Schema) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function generateCardItemSchema(component) {
|
function generateCardItemSchema(component) {
|
||||||
const defaults = {
|
const defaults: { [key: string]: ISchema } = {
|
||||||
'Markdown.Void': {
|
'Markdown.Void': {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
default: '这是一段演示文字,**支持使用 Markdown 语法**',
|
default: '这是一段演示文字,**支持使用 Markdown 语法**',
|
||||||
@ -162,6 +162,21 @@ function generateCardItemSchema(component) {
|
|||||||
fieldNames: [],
|
fieldNames: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '删除',
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'AddNew.Displayed',
|
||||||
|
'x-decorator-props': {
|
||||||
|
displayName: 'destroy',
|
||||||
|
},
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ Table.useTableDestroyAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
@ -172,6 +187,9 @@ function generateCardItemSchema(component) {
|
|||||||
displayName: 'create',
|
displayName: 'create',
|
||||||
},
|
},
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
modal: {
|
modal: {
|
||||||
@ -194,21 +212,6 @@ function generateCardItemSchema(component) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
name: 'action1',
|
|
||||||
title: '删除',
|
|
||||||
'x-align': 'right',
|
|
||||||
'x-decorator': 'AddNew.Displayed',
|
|
||||||
'x-decorator-props': {
|
|
||||||
displayName: 'destroy',
|
|
||||||
},
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ Table.useTableDestroyAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
@ -222,58 +225,67 @@ function generateCardItemSchema(component) {
|
|||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Action.Dropdown',
|
name: 'action1',
|
||||||
|
'x-component': 'Action',
|
||||||
|
// 'x-designable-bar': 'Action.DesignableBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
buttonProps: {
|
icon: 'EllipsisOutlined',
|
||||||
icon: 'EllipsisOutlined',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '操作 1',
|
'x-component': 'Action.Dropdown',
|
||||||
'x-component': 'Menu.Action',
|
'x-component-props': {},
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
minWidth: 150,
|
|
||||||
},
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
name: 'action1',
|
|
||||||
title: '查看',
|
|
||||||
'x-component': 'Menu.Action',
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '查看',
|
title: '操作 1',
|
||||||
'x-component': 'Action.Modal',
|
'x-component': 'Menu.Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
bodyStyle: {
|
style: {
|
||||||
background: '#f0f2f5',
|
minWidth: 150,
|
||||||
paddingTop: 0,
|
|
||||||
},
|
},
|
||||||
|
disabled: true,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '查看',
|
||||||
|
'x-component': 'Menu.Action',
|
||||||
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Tabs',
|
title: '查看',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
'x-component-props': {
|
||||||
|
bodyStyle: {
|
||||||
|
background: '#f0f2f5',
|
||||||
|
// paddingTop: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Tabs.TabPane',
|
'x-component': 'Tabs',
|
||||||
'x-component-props': {
|
'x-designable-bar': 'Tabs.DesignableBar',
|
||||||
tab: 'Tab1',
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
title: '详情',
|
||||||
|
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
addNewComponent: 'AddNew.PaneItem',
|
},
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-component-props': {
|
||||||
|
addNewComponent: 'AddNew.PaneItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -282,44 +294,44 @@ function generateCardItemSchema(component) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
title: '编辑',
|
|
||||||
'x-component': 'Menu.Action',
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '编辑数据',
|
title: '编辑',
|
||||||
'x-decorator': 'Form',
|
'x-component': 'Menu.Action',
|
||||||
'x-decorator-props': {
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
useResource: '{{ Table.useResource }}',
|
|
||||||
useValues: '{{ Table.useTableRowRecord }}',
|
|
||||||
},
|
|
||||||
'x-component': 'Action.Modal',
|
|
||||||
'x-component-props': {
|
|
||||||
useOkAction: '{{ Table.useTableUpdateAction }}',
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
title: '编辑数据',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-decorator-props': {
|
||||||
|
useResource: '{{ Table.useResource }}',
|
||||||
|
useValues: '{{ Table.useTableRowRecord }}',
|
||||||
|
},
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
addNewComponent: 'AddNew.FormItem',
|
useOkAction: '{{ Table.useTableUpdateAction }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-component-props': {
|
||||||
|
addNewComponent: 'AddNew.FormItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
[uid()]: {
|
||||||
},
|
type: 'void',
|
||||||
[uid()]: {
|
title: '删除',
|
||||||
type: 'void',
|
'x-component': 'Menu.Action',
|
||||||
title: '删除',
|
'x-component-props': {
|
||||||
'x-component': 'Menu.Action',
|
useAction: '{{ Table.useTableDestroyAction }}',
|
||||||
'x-component-props': {
|
},
|
||||||
useAction: '{{ Table.useTableDestroyAction }}',
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -512,7 +524,11 @@ AddNew.CardItem = observer((props: any) => {
|
|||||||
key={view.key}
|
key={view.key}
|
||||||
title={view.title}
|
title={view.title}
|
||||||
>
|
>
|
||||||
<Menu.ItemGroup className={'display-fields'} key={`${view.key}-select`} title={'所属数据表'}>
|
<Menu.ItemGroup
|
||||||
|
className={'display-fields'}
|
||||||
|
key={`${view.key}-select`}
|
||||||
|
title={'所属数据表'}
|
||||||
|
>
|
||||||
{collections?.map((item) => (
|
{collections?.map((item) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
style={{ minWidth: 150 }}
|
style={{ minWidth: 150 }}
|
||||||
|
@ -60,6 +60,13 @@ import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd';
|
|||||||
import deepmerge from 'deepmerge';
|
import deepmerge from 'deepmerge';
|
||||||
import { onFieldChange } from '@formily/core';
|
import { onFieldChange } from '@formily/core';
|
||||||
import { VisibleContext } from '../../context';
|
import { VisibleContext } from '../../context';
|
||||||
|
import {
|
||||||
|
DragHandle,
|
||||||
|
SortableItem,
|
||||||
|
SortableItemContext,
|
||||||
|
} from '../../components/Sortable';
|
||||||
|
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
export const MenuModeContext = createContext(null);
|
export const MenuModeContext = createContext(null);
|
||||||
|
|
||||||
@ -130,53 +137,71 @@ export const Menu: any = observer((props: any) => {
|
|||||||
sideMenuElement.style.display = isSubMenu ? 'block' : 'none';
|
sideMenuElement.style.display = isSubMenu ? 'block' : 'none';
|
||||||
}, [selectedKey]);
|
}, [selectedKey]);
|
||||||
|
|
||||||
|
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuModeContext.Provider value={mode}>
|
<DndContext onDragStart={(event) => {
|
||||||
<AntdMenu
|
setDragOverlayContent(event.active.data?.current?.title || '');
|
||||||
defaultSelectedKeys={defaultSelectedKeys}
|
}}>
|
||||||
{...others}
|
{createPortal(
|
||||||
mode={mode === 'mix' ? 'horizontal' : mode}
|
<DragOverlay
|
||||||
onSelect={(info) => {
|
style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}
|
||||||
if (mode === 'mix') {
|
dropAnimation={{
|
||||||
setSelectedKey(info.key);
|
duration: 10,
|
||||||
}
|
easing: 'cubic-bezier(0.18, 0.67, 0.6, 1.22)',
|
||||||
const selectedSchema = schema.properties[info.key];
|
}}
|
||||||
console.log({ selectedSchema });
|
>
|
||||||
onSelect && onSelect({ ...info, schema: selectedSchema });
|
{dragOverlayContent}
|
||||||
}}
|
</DragOverlay>,
|
||||||
>
|
document.body,
|
||||||
<RecursionField schema={schema} onlyRenderProperties />
|
|
||||||
<Menu.AddNew key={uid()} path={path}>
|
|
||||||
{/* <PlusOutlined className={'nb-add-new-icon'} /> */}
|
|
||||||
<Button
|
|
||||||
className={`nb-add-new-menu-item menu-mode-${
|
|
||||||
mode === 'mix' ? 'horizontal' : mode
|
|
||||||
}`}
|
|
||||||
block
|
|
||||||
type={mode == 'inline' ? 'dashed' : 'primary'}
|
|
||||||
>
|
|
||||||
<PlusOutlined />
|
|
||||||
</Button>
|
|
||||||
</Menu.AddNew>
|
|
||||||
</AntdMenu>
|
|
||||||
{mode === 'mix' && (
|
|
||||||
<div ref={ref}>
|
|
||||||
<SideMenu
|
|
||||||
path={path}
|
|
||||||
onSelect={(info) => {
|
|
||||||
const keyPath = [selectedKey, ...[...info.keyPath].reverse()];
|
|
||||||
const selectedSchema = findPropertyByPath(schema, keyPath);
|
|
||||||
console.log('keyPath', keyPath, selectedSchema);
|
|
||||||
onSelect &&
|
|
||||||
onSelect({ ...info, keyPath, schema: selectedSchema });
|
|
||||||
}}
|
|
||||||
defaultSelectedKeys={defaultSelectedKeys || []}
|
|
||||||
selectedKey={selectedKey}
|
|
||||||
sideMenuRef={sideMenuRef}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</MenuModeContext.Provider>
|
<MenuModeContext.Provider value={mode}>
|
||||||
|
<AntdMenu
|
||||||
|
defaultSelectedKeys={defaultSelectedKeys}
|
||||||
|
{...others}
|
||||||
|
mode={mode === 'mix' ? 'horizontal' : mode}
|
||||||
|
onSelect={(info) => {
|
||||||
|
if (mode === 'mix') {
|
||||||
|
setSelectedKey(info.key);
|
||||||
|
}
|
||||||
|
const selectedSchema = schema.properties[info.key];
|
||||||
|
console.log({ selectedSchema });
|
||||||
|
onSelect && onSelect({ ...info, schema: selectedSchema });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecursionField schema={schema} onlyRenderProperties />
|
||||||
|
<Menu.AddNew key={uid()} path={path}>
|
||||||
|
{/* <PlusOutlined className={'nb-add-new-icon'} /> */}
|
||||||
|
<Button
|
||||||
|
className={`nb-add-new-menu-item menu-mode-${
|
||||||
|
mode === 'mix' ? 'horizontal' : mode
|
||||||
|
}`}
|
||||||
|
block
|
||||||
|
type={mode == 'inline' ? 'dashed' : 'primary'}
|
||||||
|
>
|
||||||
|
<PlusOutlined />
|
||||||
|
</Button>
|
||||||
|
</Menu.AddNew>
|
||||||
|
</AntdMenu>
|
||||||
|
{mode === 'mix' && (
|
||||||
|
<div ref={ref}>
|
||||||
|
<SideMenu
|
||||||
|
path={path}
|
||||||
|
onSelect={(info) => {
|
||||||
|
const keyPath = [selectedKey, ...[...info.keyPath].reverse()];
|
||||||
|
const selectedSchema = findPropertyByPath(schema, keyPath);
|
||||||
|
console.log('keyPath', keyPath, selectedSchema);
|
||||||
|
onSelect &&
|
||||||
|
onSelect({ ...info, keyPath, schema: selectedSchema });
|
||||||
|
}}
|
||||||
|
defaultSelectedKeys={defaultSelectedKeys || []}
|
||||||
|
selectedKey={selectedKey}
|
||||||
|
sideMenuRef={sideMenuRef}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</MenuModeContext.Provider>
|
||||||
|
</DndContext>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -188,12 +213,22 @@ Menu.Item = observer((props: any) => {
|
|||||||
return (
|
return (
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
{...props}
|
{...props}
|
||||||
icon={<IconPicker type={icon} />}
|
icon={null}
|
||||||
eventKey={schema.name}
|
eventKey={schema.name}
|
||||||
key={schema.name}
|
key={schema.name}
|
||||||
>
|
>
|
||||||
{schema.title}
|
<SortableItem
|
||||||
<DesignableBar />
|
id={schema.name}
|
||||||
|
data={{
|
||||||
|
title: schema.title,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon && (
|
||||||
|
<span style={{ marginRight: 10 }}><IconPicker type={icon} /></span>
|
||||||
|
)}
|
||||||
|
{schema.title}
|
||||||
|
<DesignableBar />
|
||||||
|
</SortableItem>
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -204,11 +239,22 @@ Menu.Link = observer((props: any) => {
|
|||||||
return (
|
return (
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
{...props}
|
{...props}
|
||||||
icon={<IconPicker type={icon} />}
|
icon={null}
|
||||||
eventKey={schema.name}
|
eventKey={schema.name}
|
||||||
key={schema.name}
|
key={schema.name}
|
||||||
>
|
>
|
||||||
{schema.title}
|
<SortableItem
|
||||||
|
id={schema.name}
|
||||||
|
data={{
|
||||||
|
title: schema.title,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon && (
|
||||||
|
<span style={{ marginRight: 10 }}><IconPicker type={icon} /></span>
|
||||||
|
)}
|
||||||
|
{schema.title}
|
||||||
|
<DesignableBar />
|
||||||
|
</SortableItem>
|
||||||
{/* <Link to={props.to || schema.name}>{schema.title}</Link> */}
|
{/* <Link to={props.to || schema.name}>{schema.title}</Link> */}
|
||||||
<DesignableBar />
|
<DesignableBar />
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
@ -553,6 +599,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
}}
|
}}
|
||||||
className={'designable-bar-actions'}
|
className={'designable-bar-actions'}
|
||||||
>
|
>
|
||||||
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
overlayStyle={{
|
overlayStyle={{
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
|
226
packages/client/src/schemas/table/Sortable.tsx
Normal file
226
packages/client/src/schemas/table/Sortable.tsx
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
import React, { forwardRef, useState } from 'react';
|
||||||
|
import {
|
||||||
|
SortableContext,
|
||||||
|
useSortable,
|
||||||
|
horizontalListSortingStrategy,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
sortableKeyboardCoordinates,
|
||||||
|
} from '@dnd-kit/sortable';
|
||||||
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
|
import { Table } from 'antd';
|
||||||
|
import { createContext } from 'react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { range } from 'lodash';
|
||||||
|
import parse from 'html-react-parser';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { MenuOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DndContext,
|
||||||
|
DragOverlay,
|
||||||
|
closestCenter,
|
||||||
|
KeyboardSensor,
|
||||||
|
PointerSensor,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
useDroppable,
|
||||||
|
useDraggable,
|
||||||
|
} from '@dnd-kit/core';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { SortableItem } from '../../components/Sortable';
|
||||||
|
|
||||||
|
export const RowDraggableContext = createContext({});
|
||||||
|
export const ColDraggableContext = createContext(null);
|
||||||
|
export const CellContext = createContext(null);
|
||||||
|
|
||||||
|
export function SortableColumn(props) {
|
||||||
|
const { className } = props;
|
||||||
|
const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
||||||
|
id: `droppable-${props['id']}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
isDragging,
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef: setDraggableNodeRef,
|
||||||
|
transform,
|
||||||
|
} = useDraggable({
|
||||||
|
id: `draggable-${props['id']}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
className={cls(className, `draggable-${props['id']}`, {
|
||||||
|
isOver,
|
||||||
|
isDragging,
|
||||||
|
})}
|
||||||
|
ref={setDroppableNodeRef}
|
||||||
|
// {...attributes}
|
||||||
|
>
|
||||||
|
<ColDraggableContext.Provider
|
||||||
|
value={{ setDraggableNodeRef, attributes, listeners }}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</ColDraggableContext.Provider>
|
||||||
|
{/* <span ref={setDraggableNodeRef} {...attributes} {...listeners}>
|
||||||
|
Drag
|
||||||
|
</span> */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableBodyRow(props: any) {
|
||||||
|
const {
|
||||||
|
className,
|
||||||
|
style: prevStyle,
|
||||||
|
['data-row-key']: dataRowKey,
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
|
const {
|
||||||
|
isDragging,
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef,
|
||||||
|
setDraggableNodeRef,
|
||||||
|
overIndex,
|
||||||
|
transform,
|
||||||
|
transition,
|
||||||
|
} = useSortable({ id: dataRowKey });
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
...prevStyle,
|
||||||
|
transform: CSS.Transform.toString(transform),
|
||||||
|
transition,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RowDraggableContext.Provider
|
||||||
|
value={{ listeners, setDraggableNodeRef, attributes }}
|
||||||
|
>
|
||||||
|
<tr
|
||||||
|
className={cls(
|
||||||
|
{ isDragging },
|
||||||
|
props.className,
|
||||||
|
`droppable-${props['data-row-key']}`,
|
||||||
|
)}
|
||||||
|
// className={cls(className)}
|
||||||
|
ref={setNodeRef}
|
||||||
|
{...others}
|
||||||
|
{...attributes}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<SortableContext
|
||||||
|
strategy={horizontalListSortingStrategy}
|
||||||
|
items={React.Children.map(props.children, (child) => {
|
||||||
|
console.log(child.key, 'child.key');
|
||||||
|
return `td${child.key}`;
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{React.Children.map(props.children, (child, index) => (
|
||||||
|
<CellContext.Provider value={`td${child.key}`}>
|
||||||
|
{child}
|
||||||
|
</CellContext.Provider>
|
||||||
|
))}
|
||||||
|
</SortableContext>
|
||||||
|
</tr>
|
||||||
|
</RowDraggableContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableHeaderRow(props) {
|
||||||
|
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
||||||
|
return (
|
||||||
|
<tr {...props}>
|
||||||
|
<DndContext
|
||||||
|
onDragStart={(event) => {
|
||||||
|
const previewRef = event.active.data?.current?.previewRef as {
|
||||||
|
current: HTMLElement;
|
||||||
|
};
|
||||||
|
if (previewRef?.current) {
|
||||||
|
setDragOverlayContent(previewRef.current.textContent || '');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{createPortal(
|
||||||
|
<DragOverlay style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}>
|
||||||
|
{dragOverlayContent}
|
||||||
|
</DragOverlay>,
|
||||||
|
document.body,
|
||||||
|
)}
|
||||||
|
{React.Children.map(props.children, (child, index) => (
|
||||||
|
<CellContext.Provider value={child.key}>{child}</CellContext.Provider>
|
||||||
|
))}
|
||||||
|
</DndContext>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableHeaderCell(props) {
|
||||||
|
const id = useContext(CellContext);
|
||||||
|
if (['RC_TABLE_KEY', 'addnew'].includes(id)) {
|
||||||
|
return <th {...props} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<SortableItem
|
||||||
|
{...props}
|
||||||
|
id={id}
|
||||||
|
component={forwardRef<any>((props, ref) => (
|
||||||
|
<th ref={ref} {...props} />
|
||||||
|
))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableBodyCell(props) {
|
||||||
|
const id = useContext(CellContext);
|
||||||
|
const {
|
||||||
|
isDragging,
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef,
|
||||||
|
setDraggableNodeRef,
|
||||||
|
setDroppableNodeRef,
|
||||||
|
transform,
|
||||||
|
transition,
|
||||||
|
} = useSortable({ id: id });
|
||||||
|
const style = {
|
||||||
|
...props.style,
|
||||||
|
transform: CSS.Transform.toString(transform),
|
||||||
|
transition,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<td
|
||||||
|
ref={setDroppableNodeRef}
|
||||||
|
{...props}
|
||||||
|
className={cls({ isDragging }, props.className)}
|
||||||
|
// {...attributes}
|
||||||
|
// {...listeners}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<div style={{ height: 0, width: 0, opacity: 0, overflow: 'hidden' }}>
|
||||||
|
<span ref={setDraggableNodeRef} {...attributes} {...listeners}>
|
||||||
|
Drag
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{props.children}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableRowHandle(props) {
|
||||||
|
const { className, ...others } = props;
|
||||||
|
const { setDraggableNodeRef, attributes, listeners } =
|
||||||
|
useContext<any>(RowDraggableContext);
|
||||||
|
return setDraggableNodeRef ? (
|
||||||
|
<MenuOutlined
|
||||||
|
{...others}
|
||||||
|
// ref={setDraggableNodeRef}
|
||||||
|
// {...attributes}
|
||||||
|
{...listeners}
|
||||||
|
className={cls(`nb-table-sort-handle`, className)}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
}
|
@ -18,8 +18,12 @@ import useRequest from '@ahooksjs/use-request';
|
|||||||
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
import { DndContext } from '@dnd-kit/core';
|
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
||||||
import { SortableContext, useSortable } from '@dnd-kit/sortable';
|
import {
|
||||||
|
SortableContext,
|
||||||
|
useSortable,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
} from '@dnd-kit/sortable';
|
||||||
import { CSS } from '@dnd-kit/utilities';
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd';
|
import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
@ -44,6 +48,16 @@ import { useResource as useGeneralResource } from '../../hooks/useResource';
|
|||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
|
import {
|
||||||
|
ColDraggableContext,
|
||||||
|
SortableBodyCell,
|
||||||
|
SortableBodyRow,
|
||||||
|
SortableColumn,
|
||||||
|
SortableHeaderCell,
|
||||||
|
SortableHeaderRow,
|
||||||
|
SortableRowHandle,
|
||||||
|
} from './Sortable';
|
||||||
|
import { DragHandle, SortableItem } from '../../components/Sortable';
|
||||||
|
|
||||||
const SyntheticListenerMapContext = createContext(null);
|
const SyntheticListenerMapContext = createContext(null);
|
||||||
|
|
||||||
@ -272,7 +286,7 @@ const useTableColumns = () => {
|
|||||||
const columnProps = column['x-component-props'] || {};
|
const columnProps = column['x-component-props'] || {};
|
||||||
const collectionField = getField(columnProps.fieldName);
|
const collectionField = getField(columnProps.fieldName);
|
||||||
return {
|
return {
|
||||||
title: (
|
title: () => (
|
||||||
<CollectionFieldContext.Provider value={collectionField}>
|
<CollectionFieldContext.Provider value={collectionField}>
|
||||||
<RecursionField name={column.name} schema={column} onlyRenderSelf />
|
<RecursionField name={column.name} schema={column} onlyRenderSelf />
|
||||||
</CollectionFieldContext.Provider>
|
</CollectionFieldContext.Provider>
|
||||||
@ -402,6 +416,7 @@ const TableMain = () => {
|
|||||||
const columns = useTableColumns();
|
const columns = useTableColumns();
|
||||||
const dataSource = useDataSource();
|
const dataSource = useDataSource();
|
||||||
const actionBars = useTableActionBars();
|
const actionBars = useTableActionBars();
|
||||||
|
const [html, setHtml] = useState('');
|
||||||
return (
|
return (
|
||||||
<div className={'nb-table'}>
|
<div className={'nb-table'}>
|
||||||
<DndContext
|
<DndContext
|
||||||
@ -421,7 +436,10 @@ const TableMain = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<SortableContext items={dataSource}>
|
<SortableContext
|
||||||
|
items={dataSource}
|
||||||
|
strategy={verticalListSortingStrategy}
|
||||||
|
>
|
||||||
<AntdTable
|
<AntdTable
|
||||||
pagination={false}
|
pagination={false}
|
||||||
onChange={(pagination) => {}}
|
onChange={(pagination) => {}}
|
||||||
@ -429,9 +447,32 @@ const TableMain = () => {
|
|||||||
rowKey={rowKey}
|
rowKey={rowKey}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
// components={{
|
||||||
|
// body: {
|
||||||
|
// row: DragableBodyRow,
|
||||||
|
// },
|
||||||
|
// }}
|
||||||
components={{
|
components={{
|
||||||
|
header: {
|
||||||
|
row: SortableHeaderRow,
|
||||||
|
cell: SortableHeaderCell,
|
||||||
|
},
|
||||||
body: {
|
body: {
|
||||||
row: DragableBodyRow,
|
// wrapper: (props) => {
|
||||||
|
// return (
|
||||||
|
// <tbody {...props}>
|
||||||
|
// <DragOverlay
|
||||||
|
// className={'ant-table-row'}
|
||||||
|
// wrapperElement={'tr'}
|
||||||
|
// >
|
||||||
|
// <div />
|
||||||
|
// </DragOverlay>
|
||||||
|
// {props.children}
|
||||||
|
// </tbody>
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
row: SortableBodyRow,
|
||||||
|
// cell: SortableBodyCell,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
@ -749,7 +790,11 @@ function Actions(props: any) {
|
|||||||
if (currentAlign !== align) {
|
if (currentAlign !== align) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return <RecursionField name={s.name} schema={s} />;
|
return (
|
||||||
|
<SortableItem id={s.name} data={{ title: s.title }}>
|
||||||
|
<RecursionField name={s.name} schema={s} />
|
||||||
|
</SortableItem>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
@ -758,20 +803,33 @@ function Actions(props: any) {
|
|||||||
Table.ActionBar = observer((props: any) => {
|
Table.ActionBar = observer((props: any) => {
|
||||||
const { align = 'top' } = props;
|
const { align = 'top' } = props;
|
||||||
const { schema, designable } = useDesignable();
|
const { schema, designable } = useDesignable();
|
||||||
const designableBar = schema['x-designable-bar'];
|
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
||||||
console.log('Table.ActionBar', { schema });
|
|
||||||
return (
|
return (
|
||||||
<DisplayedMapProvider>
|
<DndContext onDragStart={(event) => {
|
||||||
<div className={cls('nb-action-bar', `align-${align}`)}>
|
setDragOverlayContent(event.active.data?.current?.title || '');
|
||||||
<div>
|
// const previewRef = event.active.data?.current?.previewRef;
|
||||||
<Actions align={'left'} />
|
// if (previewRef) {
|
||||||
|
// setDragOverlayContent(previewRef?.current?.innerHTML);
|
||||||
|
// } else {
|
||||||
|
// setDragOverlayContent('');
|
||||||
|
// }
|
||||||
|
}}>
|
||||||
|
<DragOverlay style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}>
|
||||||
|
{dragOverlayContent}
|
||||||
|
{/* <div style={{ transform: 'translateX(-100%)' }} dangerouslySetInnerHTML={{__html: dragOverlayContent}}></div> */}
|
||||||
|
</DragOverlay>
|
||||||
|
<DisplayedMapProvider>
|
||||||
|
<div className={cls('nb-action-bar', `align-${align}`)}>
|
||||||
|
<div style={{ width: '50%' }}>
|
||||||
|
<Actions align={'left'} />
|
||||||
|
</div>
|
||||||
|
<div style={{ marginLeft: 'auto', width: '50%', textAlign: 'right' }}>
|
||||||
|
<Actions align={'right'} />
|
||||||
|
</div>
|
||||||
|
<AddActionButton />
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginLeft: 'auto' }}>
|
</DisplayedMapProvider>
|
||||||
<Actions align={'right'} />
|
</DndContext>
|
||||||
</div>
|
|
||||||
<AddActionButton />
|
|
||||||
</div>
|
|
||||||
</DisplayedMapProvider>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -922,6 +980,7 @@ Table.OperationDesignableBar = () => {
|
|||||||
}}
|
}}
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
>
|
>
|
||||||
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -975,6 +1034,7 @@ Table.Action.DesignableBar = () => {
|
|||||||
}}
|
}}
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
>
|
>
|
||||||
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -1090,6 +1150,7 @@ Table.Column.DesignableBar = () => {
|
|||||||
const { schema, remove, refresh, insertAfter } = useDesignable();
|
const { schema, remove, refresh, insertAfter } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const displayed = useDisplayedMapContext();
|
const displayed = useDisplayedMapContext();
|
||||||
|
const ctx = useContext(ColDraggableContext);
|
||||||
return (
|
return (
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
<span
|
<span
|
||||||
@ -1098,6 +1159,7 @@ Table.Column.DesignableBar = () => {
|
|||||||
}}
|
}}
|
||||||
className={cls('designable-bar-actions', { active: visible })}
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
>
|
>
|
||||||
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -1147,16 +1209,7 @@ Table.Index = observer(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Table.SortHandle = observer((props: any) => {
|
Table.SortHandle = observer((props: any) => {
|
||||||
const listeners = useContext(SyntheticListenerMapContext);
|
return <SortableRowHandle {...props} />;
|
||||||
const { className, ...others } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuOutlined
|
|
||||||
{...listeners}
|
|
||||||
className={cls(`nb-table-sort-handle`, className)}
|
|
||||||
{...others}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Table.DesignableBar = observer((props) => {
|
Table.DesignableBar = observer((props) => {
|
||||||
|
@ -44,11 +44,18 @@ const schema = {
|
|||||||
properties: {
|
properties: {
|
||||||
tabs: {
|
tabs: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
'x-decorator': 'Card',
|
||||||
'x-component': 'Tabs',
|
'x-component': 'Tabs',
|
||||||
|
'x-designable-bar': 'Tabs.DesignableBar',
|
||||||
|
'x-component-props': {
|
||||||
|
// singleton: true,
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
tab1: {
|
tab1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
title: 'Tab1',
|
||||||
'x-component': 'Tabs.TabPane',
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
tab: 'Tab1',
|
tab: 'Tab1',
|
||||||
},
|
},
|
||||||
@ -64,7 +71,9 @@ const schema = {
|
|||||||
},
|
},
|
||||||
tab2: {
|
tab2: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
title: 'Tab2',
|
||||||
'x-component': 'Tabs.TabPane',
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
tab: 'Tab2',
|
tab: 'Tab2',
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,228 @@
|
|||||||
import { observer, connect } from '@formily/react';
|
import { observer, connect, useField, RecursionField } from '@formily/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormTab } from '@formily/antd';
|
import { Button, Tabs as AntdTabs, Dropdown, Menu, Switch } from 'antd';
|
||||||
import '@formily/antd/lib/form-tab/style';
|
import { useDesignable } from '../../components/schema-renderer';
|
||||||
|
import { Schema, SchemaKey } from '@formily/react';
|
||||||
|
import { PlusOutlined, MenuOutlined } from '@ant-design/icons';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { createSchema, removeSchema } from '..';
|
||||||
|
import './style.less';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { DragHandle, SortableItem } from '../../components/Sortable';
|
||||||
|
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
||||||
|
|
||||||
export const Tabs = FormTab;
|
const useTabs = () => {
|
||||||
|
const tabsField = useField();
|
||||||
|
const { schema } = useDesignable();
|
||||||
|
const tabs: { name: SchemaKey; props: any; schema: Schema }[] = [];
|
||||||
|
schema.mapProperties((schema, name) => {
|
||||||
|
const field = tabsField.query(tabsField.address.concat(name)).take();
|
||||||
|
if (field?.display === 'none' || field?.display === 'hidden') return;
|
||||||
|
if (schema['x-component']?.indexOf('TabPane') > -1) {
|
||||||
|
tabs.push({
|
||||||
|
name,
|
||||||
|
props: {
|
||||||
|
key: schema?.['x-component-props']?.key || name,
|
||||||
|
...schema?.['x-component-props'],
|
||||||
|
},
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return tabs;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Tabs: any = observer((props: any) => {
|
||||||
|
const { singleton, ...others } = props;
|
||||||
|
const { schema, DesignableBar, appendChild } = useDesignable();
|
||||||
|
const tabs = useTabs();
|
||||||
|
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
||||||
|
|
||||||
|
if (singleton) {
|
||||||
|
return (
|
||||||
|
<div className={'nb-tabs'}>
|
||||||
|
<DesignableBar />
|
||||||
|
{tabs.map(({ props, schema, name }, key) => (
|
||||||
|
<RecursionField schema={schema} name={name} onlyRenderProperties />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'nb-tabs'}>
|
||||||
|
<DesignableBar />
|
||||||
|
<DndContext
|
||||||
|
onDragStart={(event) => {
|
||||||
|
setDragOverlayContent(event.active.data?.current?.title || '');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DragOverlay style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}>
|
||||||
|
{dragOverlayContent}
|
||||||
|
</DragOverlay>
|
||||||
|
<AntdTabs
|
||||||
|
{...others}
|
||||||
|
className={cls({ singleton })}
|
||||||
|
tabBarExtraContent={
|
||||||
|
<Button
|
||||||
|
type={'dashed'}
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={async () => {
|
||||||
|
const data = appendChild({
|
||||||
|
type: 'void',
|
||||||
|
name: uid(),
|
||||||
|
title: uid(),
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
|
||||||
|
'x-component-props': {
|
||||||
|
tab: uid(),
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-component-props': {
|
||||||
|
addNewComponent: 'AddNew.PaneItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await createSchema(data);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
新增标签页
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tabs.map(({ props, schema, name }, key) => (
|
||||||
|
<AntdTabs.TabPane
|
||||||
|
{...props}
|
||||||
|
tab={
|
||||||
|
<RecursionField schema={schema} name={name} onlyRenderSelf />
|
||||||
|
}
|
||||||
|
key={key}
|
||||||
|
>
|
||||||
|
<RecursionField
|
||||||
|
schema={schema}
|
||||||
|
name={name}
|
||||||
|
onlyRenderProperties
|
||||||
|
/>
|
||||||
|
</AntdTabs.TabPane>
|
||||||
|
))}
|
||||||
|
</AntdTabs>
|
||||||
|
</DndContext>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Tabs.TabPane = observer((props: any) => {
|
||||||
|
const { schema, DesignableBar } = useDesignable();
|
||||||
|
return (
|
||||||
|
<SortableItem
|
||||||
|
id={schema.name}
|
||||||
|
data={{
|
||||||
|
title: schema.title,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={'nb-tab-pane'}>
|
||||||
|
{schema.title} <DesignableBar />
|
||||||
|
</div>
|
||||||
|
</SortableItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Tabs.DesignableBar = () => {
|
||||||
|
const { schema, remove, refresh, insertAfter } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const field = useField();
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
placement={'bottomRight'}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item
|
||||||
|
onClick={async () => {
|
||||||
|
const singleton = !field.componentProps.singleton;
|
||||||
|
schema['x-component-props'] =
|
||||||
|
schema['x-component-props'] || {};
|
||||||
|
schema['x-component-props'].singleton = singleton;
|
||||||
|
field.componentProps.singleton = singleton;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
禁用标签页 <span style={{ marginRight: 24 }}></span>{' '}
|
||||||
|
<Switch size={'small'} />
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tabs.TabPane.DesignableBar = () => {
|
||||||
|
const { schema, remove, refresh, insertAfter } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<DragHandle />{' '}
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item
|
||||||
|
onClick={() => {
|
||||||
|
schema.title = uid();
|
||||||
|
schema['x-component-props'] =
|
||||||
|
schema['x-component-props'] || {};
|
||||||
|
schema['x-component-props']['tab'] = uid();
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
修改名称和图标
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.Item
|
||||||
|
onClick={async () => {
|
||||||
|
const data = remove();
|
||||||
|
await removeSchema(data);
|
||||||
|
setVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
78
packages/client/src/schemas/tabs/style.less
Normal file
78
packages/client/src/schemas/tabs/style.less
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
.nb-tabs,
|
||||||
|
.nb-tab-pane {
|
||||||
|
&:hover {
|
||||||
|
> .designable-bar {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .designable-bar {
|
||||||
|
pointer-events: none;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -16px;
|
||||||
|
left: -16px;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
border: 2px solid #1890ff;
|
||||||
|
&.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.designable-bar-actions {
|
||||||
|
pointer-events: all;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
line-height: 1rem;
|
||||||
|
background-color: #1890ff;
|
||||||
|
color: #fff;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 0 3px;
|
||||||
|
.anticon {
|
||||||
|
font-size: 10px;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ant-tabs-tab:first-child {
|
||||||
|
.nb-tab-pane {
|
||||||
|
.designable-bar {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-tabs-tab:last-child {
|
||||||
|
.nb-tab-pane {
|
||||||
|
.designable-bar {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-tabs-dropdown-menu-item {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-tabs.singleton {
|
||||||
|
.ant-tabs-nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nb-tabs {
|
||||||
|
position: relative;
|
||||||
|
> .designable-bar {
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-body,
|
||||||
|
.ant-modal-body {
|
||||||
|
.nb-tabs {
|
||||||
|
margin: -24px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
}
|
36
yarn.lock
36
yarn.lock
@ -7571,7 +7571,7 @@ domexception@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
webidl-conversions "^5.0.0"
|
webidl-conversions "^5.0.0"
|
||||||
|
|
||||||
domhandler@^4.0.0, domhandler@^4.2.0:
|
domhandler@4.2.0, domhandler@^4.0.0, domhandler@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
|
resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
|
||||||
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
|
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
|
||||||
@ -9645,6 +9645,14 @@ hsla-regex@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
|
resolved "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
|
||||||
integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
|
integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
|
||||||
|
|
||||||
|
html-dom-parser@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-1.0.1.tgz#5d147fed6656c12918edbcea4a423eefe8d0e715"
|
||||||
|
integrity sha512-uKXISKlHzB/l9A08jrs2wseQJ9b864ZfEdmIZskj10cuP6HxCOMHSK0RdluV8NVQaWs0PwefN7d8wqG3jR0IbQ==
|
||||||
|
dependencies:
|
||||||
|
domhandler "4.2.0"
|
||||||
|
htmlparser2 "6.1.0"
|
||||||
|
|
||||||
html-element-map@^1.2.0:
|
html-element-map@^1.2.0:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.npmjs.org/html-element-map/-/html-element-map-1.3.1.tgz#44b2cbcfa7be7aa4ff59779e47e51012e1c73c08"
|
resolved "https://registry.npmjs.org/html-element-map/-/html-element-map-1.3.1.tgz#44b2cbcfa7be7aa4ff59779e47e51012e1c73c08"
|
||||||
@ -9672,12 +9680,22 @@ html-escaper@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
|
resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
|
||||||
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
||||||
|
|
||||||
|
html-react-parser@^1.2.7:
|
||||||
|
version "1.2.7"
|
||||||
|
resolved "https://registry.npmjs.org/html-react-parser/-/html-react-parser-1.2.7.tgz#1674ed4b96b3440ad922962a3ff000e7f3325293"
|
||||||
|
integrity sha512-gUUEgrZV0YaCxtZO2XuJDUnHSq7gOqKu1krye97cxgiZ+ipaIzspGMhATeq9lhy9gwYmwBF2YCHe/accrMMo8Q==
|
||||||
|
dependencies:
|
||||||
|
domhandler "4.2.0"
|
||||||
|
html-dom-parser "1.0.1"
|
||||||
|
react-property "1.0.1"
|
||||||
|
style-to-js "1.1.0"
|
||||||
|
|
||||||
html-void-elements@^1.0.0:
|
html-void-elements@^1.0.0:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483"
|
resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483"
|
||||||
integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==
|
integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==
|
||||||
|
|
||||||
htmlparser2@^6.1.0:
|
htmlparser2@6.1.0, htmlparser2@^6.1.0:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
||||||
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
|
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
|
||||||
@ -15976,6 +15994,11 @@ react-native-swipeout@^2.2.2:
|
|||||||
prop-types "^15.5.10"
|
prop-types "^15.5.10"
|
||||||
react-tween-state "^0.1.5"
|
react-tween-state "^0.1.5"
|
||||||
|
|
||||||
|
react-property@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/react-property/-/react-property-1.0.1.tgz#4ae4211557d0a0ae050a71aa8ad288c074bea4e6"
|
||||||
|
integrity sha512-1tKOwxFn3dXVomH6pM9IkLkq2Y8oh+fh/lYW3MJ/B03URswUTqttgckOlbxY2XHF3vPG6uanSc4dVsLW/wk3wQ==
|
||||||
|
|
||||||
react-redux@^7.1.0:
|
react-redux@^7.1.0:
|
||||||
version "7.2.4"
|
version "7.2.4"
|
||||||
resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
|
resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
|
||||||
@ -18024,7 +18047,14 @@ style-inject@^0.3.0:
|
|||||||
resolved "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3"
|
resolved "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3"
|
||||||
integrity sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==
|
integrity sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==
|
||||||
|
|
||||||
style-to-object@^0.3.0:
|
style-to-js@1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.0.tgz#631cbb20fce204019b3aa1fcb5b69d951ceac4ac"
|
||||||
|
integrity sha512-1OqefPDxGrlMwcbfpsTVRyzwdhr4W0uxYQzeA2F1CBc8WG04udg2+ybRnvh3XYL4TdHQrCahLtax2jc8xaE6rA==
|
||||||
|
dependencies:
|
||||||
|
style-to-object "0.3.0"
|
||||||
|
|
||||||
|
style-to-object@0.3.0, style-to-object@^0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46"
|
resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46"
|
||||||
integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==
|
integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==
|
||||||
|
Loading…
Reference in New Issue
Block a user