mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: Container支持可拖拽 (#5949)
This commit is contained in:
parent
71c7378e3d
commit
88005c5422
@ -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",
|
||||
|
102
packages/amis-ui/src/components/DndContainer.tsx
Normal file
102
packages/amis-ui/src/components/DndContainer.tsx
Normal 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));
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user