feat: Container支持可拖拽 (#5949)

This commit is contained in:
RUNZE LU 2023-01-03 20:35:42 +08:00 committed by GitHub
parent 71c7378e3d
commit 88005c5422
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 203 additions and 9 deletions

View File

@ -58,6 +58,7 @@
"rc-input-number": "^7.4.0",
"rc-progress": "^3.1.4",
"react-color": "^2.19.3",
"react-draggable": "^4.4.5",
"react-hook-form": "7.39.0",
"react-json-view": "1.21.3",
"react-overlays": "5.1.1",

View File

@ -0,0 +1,102 @@
/**
* @file DndContainer
* @desc
*/
import React from 'react';
import Draggable from 'react-draggable';
import {localeable, LocaleProps, themeable, ThemeProps} from 'amis-core';
import type {
DraggableEvent,
DraggableData,
DraggableBounds
} from 'react-draggable';
export interface DndContainerProps extends LocaleProps, ThemeProps {
/**
* , , X或Y轴
*/
axis?: 'both' | 'x' | 'y' | 'none';
/** 元素的位置 */
position?: {x: number; y: number};
/** 元素的起始位置 */
defaultPosition?: {x: number; y: number};
/**
* , ,
*/
bounds?: DraggableBounds | string;
/** 以网格范围拖拽的步长 */
grid?: [number, number];
/** 初始化拖拽的选择器 */
handle?: string;
/** 禁止拖拽的选择器 */
cancel?: string;
/** 拖拽距离的缩放比, 默认为1 */
scale?: number;
/** 是否禁止拖拽 */
draggable?: boolean;
/** 默认设置容器内部为'user-select:none', 可以设置true关闭 */
enableUserSelect?: boolean;
nodeRef?: React.RefObject<HTMLElement>;
children?: React.ReactElement<any>;
onStart?: (event: DraggableEvent, data: DraggableData) => void | false;
onDrag?: (event: DraggableEvent, data: DraggableData) => void | false;
onStop?: (event: DraggableEvent, data: DraggableData) => void | false;
}
const DndContainer: React.FC<DndContainerProps> = (
props: DndContainerProps
) => {
const {
className,
classnames: cx,
children,
axis,
position,
defaultPosition,
bounds,
grid,
handle,
cancel,
draggable,
scale,
enableUserSelect,
nodeRef,
onDrag,
onStart,
onStop
} = props;
return (
<Draggable
axis={axis}
position={position}
defaultPosition={defaultPosition}
bounds={bounds}
grid={grid}
handle={handle}
cancel={cancel}
disabled={!draggable}
scale={scale}
enableUserSelectHack={!enableUserSelect}
nodeRef={nodeRef}
defaultClassName={cx(className)}
defaultClassNameDragging={cx('DndContainer--dragging')}
defaultClassNameDragged={cx('DndContainer--dragged')}
onStart={onStart}
onDrag={onDrag}
onStop={onStop}
>
{children}
</Draggable>
);
};
DndContainer.defaultProps = {
axis: 'both',
scale: 1,
enableUserSelect: false
};
export default localeable(themeable(DndContainer));

View File

@ -119,6 +119,7 @@ import Combo from './Combo';
import InputTable from './InputTable';
import type {InputTableColumnProps} from './InputTable';
import ConfirmBox from './ConfirmBox';
import DndContainer from './DndContainer';
export {
NotFound,
@ -242,5 +243,6 @@ export {
Controller,
Combo,
InputTable,
InputTableColumnProps
InputTableColumnProps,
DndContainer
};

View File

@ -1,7 +1,64 @@
import React from 'react';
import {Renderer, RendererProps} from 'amis-core';
import merge from 'lodash/merge';
import {
Renderer,
RendererProps,
buildStyle,
isPureVariable,
resolveVariableAndFilter
} from 'amis-core';
import {DndContainer as DndWrapper} from 'amis-ui';
import {BaseSchema, SchemaClassName, SchemaCollection} from '../Schema';
import {buildStyle} from 'amis-core';
/** 容器拖拽配置 */
export interface ContainerDraggableConfig {
/**
* , , X或Y轴
*/
axis?: 'both' | 'x' | 'y';
/**
*
*/
defaultPosition?: {x: number; y: number};
/**
* , ,
*/
bounds?:
| {
left?: number;
right?: number;
top?: number;
bottom?: number;
}
| string;
/**
*
*/
grid?: [number, number];
/**
*
*/
handle?: string;
/**
*
*/
cancel?: string;
/**
* , 1
*/
scale?: number;
/**
* 'user-select:none', true关闭
*/
enableUserSelect?: boolean;
}
/**
* Container
@ -39,11 +96,21 @@ export interface ContainerSchema extends BaseSchema {
* body加一层div包裹 true
*/
wrapperBody?: boolean;
/**
*
*/
draggable?: boolean | string;
/**
*
*/
draggableConfig: ContainerDraggableConfig | string;
}
export interface ContainerProps
extends RendererProps,
Omit<ContainerSchema, 'type' | 'className'> {
Omit<ContainerSchema, 'type' | 'className' | 'style'> {
children?: (props: any) => React.ReactNode;
}
@ -53,7 +120,12 @@ export default class Container<T> extends React.Component<
> {
static propsList: Array<string> = ['body', 'className'];
static defaultProps = {
className: ''
className: '',
draggableConfig: {
axis: 'both' as ContainerDraggableConfig['axis'],
scale: 1,
enableUserSelect: false
}
};
renderBody(): JSX.Element | null {
@ -95,13 +167,22 @@ export default class Container<T> extends React.Component<
size,
classnames: cx,
style,
data
data,
draggable,
draggableConfig
} = this.props;
const finalDraggable: boolean = isPureVariable(draggable)
? resolveVariableAndFilter(draggable, data, '| raw')
: draggable;
const finalDraggableConfig: ContainerDraggableConfig = merge(
Container.defaultProps.draggableConfig,
isPureVariable(draggableConfig)
? resolveVariableAndFilter(draggableConfig, data, '| raw')
: draggableConfig
);
const Component =
(wrapperComponent as keyof JSX.IntrinsicElements) || 'div';
return (
const contentDom = (
<Component
className={cx(
'Container',
@ -113,6 +194,14 @@ export default class Container<T> extends React.Component<
{this.renderBody()}
</Component>
);
return finalDraggable ? (
<DndWrapper {...finalDraggableConfig} draggable={true}>
{contentDom}
</DndWrapper>
) : (
contentDom
);
}
}