add placeholder when drag component to grid

This commit is contained in:
Bowen Tan 2021-10-18 15:25:58 +08:00
parent 54fbe286ed
commit 454e8b8c43
7 changed files with 74 additions and 8 deletions

View File

@ -9,6 +9,7 @@ import {
Flex,
Box,
} from '@chakra-ui/react';
import { encodeDragDataTransfer, DROP_EXAMPLE_SIZE_PREFIX } from '@meta-ui/runtime';
import { registry } from '../../metaUI';
export const ComponentList: React.FC = () => {
@ -26,6 +27,15 @@ export const ComponentList: React.FC = () => {
{Array.from(registry.components.get(version)!.values()).map(c => {
const onDragStart = (e: any) => {
e.dataTransfer.setData('component', `${c.version}/${c.metadata.name}`);
// pass the exampleSize to gridlayout to render placeholder
e.dataTransfer.setData(
encodeDragDataTransfer(
`${DROP_EXAMPLE_SIZE_PREFIX}${JSON.stringify(
c.metadata.exampleSize
)}`
),
''
);
};
const cEle = (
<Flex

View File

@ -1,11 +1,17 @@
import RGL from 'react-grid-layout';
import React from 'react';
import { css } from '@emotion/react';
import { useResizeDetector } from 'react-resize-detector';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { GRID_HEIGHT } from '../../constants';
import { DROP_EXAMPLE_SIZE_PREFIX, GRID_HEIGHT } from '../../constants';
import { decodeDragDataTransfer } from '../../utils/encodeDragDataTransfer';
const GridLayout: React.FC<ReactGridLayout.ReactGridLayoutProps> = props => {
// hack: add onDropDragOver to ReactGridLayoutProps definition
const ReactGridLayout: React.FC<RGL.ReactGridLayoutProps & { onDropDragOver: any }> =
RGL as any;
const GridLayout: React.FC<RGL.ReactGridLayoutProps> = props => {
const { children } = props;
const spacing = 10;
const { width, ref } = useResizeDetector();
@ -19,22 +25,33 @@ const GridLayout: React.FC<ReactGridLayout.ReactGridLayoutProps> = props => {
background-position: 0px ${spacing / 2}px;
`;
const onDropDragOver = (e: React.DragEvent) => {
// Here we need to get data in dataTransfer
// but normally we cannot access dataTransfer in onDragOver, so I use a hack
// I use the key of dataTransfer to store data, the key will look like 'exampleSize: [1,4]'
// https://stackoverflow.com/questions/28487352/dragndrop-datatransfer-getdata-empty
const key = e.dataTransfer.types
.map(decodeDragDataTransfer)
.find(t => t.startsWith(DROP_EXAMPLE_SIZE_PREFIX));
const componentSize = JSON.parse(key?.replace(DROP_EXAMPLE_SIZE_PREFIX, '') || '');
return { w: componentSize[0], h: componentSize[1] };
};
return (
<div ref={ref} css={bgCss}>
<RGL
<ReactGridLayout
cols={12}
// isDraggable={!!onDragStop}
// isResizable={!!onDragStop}
compactType={null}
preventCollision={true}
rowHeight={GRID_HEIGHT}
width={width || 0}
margin={[spacing, spacing]}
isDroppable={true}
onDropDragOver={onDropDragOver}
{...props}
>
{children}
</RGL>
</ReactGridLayout>
</div>
);
};

View File

@ -20,7 +20,16 @@ const HStack: ComponentImplementation<Static<typeof PropsSchema>> = ({
slotsMap,
}) => {
return (
<BaseHStack {...{ direction, wrap, align, justify, spacing }}>
<BaseHStack
height="full"
width="full"
padding="4"
background="white"
border="1px solid"
borderColor="gray.200"
borderRadius="4"
{...{ direction, wrap, align, justify, spacing }}
>
<Slot slotsMap={slotsMap} slot="content" />
</BaseHStack>
);

View File

@ -20,7 +20,16 @@ const VStack: ComponentImplementation<Static<typeof PropsSchema>> = ({
slotsMap,
}) => {
return (
<BaseVStack {...{ direction, wrap, align, justify, spacing }}>
<BaseVStack
width="full"
height="full"
padding="4"
background="white"
border="1px solid"
borderColor="gray.200"
borderRadius="4"
{...{ direction, wrap, align, justify, spacing }}
>
<Slot slotsMap={slotsMap} slot="content" />
</BaseVStack>
);

View File

@ -2,3 +2,4 @@ export const LIST_ITEM_EXP = '$listItem';
export const LIST_ITEM_INDEX_EXP = '$i';
export const GRID_HEIGHT = 40;
export const DIALOG_CONTAINER_ID = 'meta-ui-dialog-container';
export const DROP_EXAMPLE_SIZE_PREFIX = 'exampleSize: ';

View File

@ -23,5 +23,6 @@ export function initMetaUI() {
export * from './utils/parseType';
export * from './utils/parseTypeBox';
export * from './utils/encodeDragDataTransfer';
export * from './types/RuntimeSchema';
export * from './constants';

View File

@ -0,0 +1,19 @@
// https://stackoverflow.com/questions/28487352/dragndrop-datatransfer-getdata-empty
const UPPERCASE_PREFIX = '^{';
const UPPERCASE_SUFFIX = '}^';
export function encodeDragDataTransfer(str: string): string {
return str.replace(/([A-Z]+)/g, `${UPPERCASE_PREFIX}$1${UPPERCASE_SUFFIX}`);
}
export function decodeDragDataTransfer(str: string): string {
const escapeRegExp = (escape: string) => ['', ...escape.split('')].join('\\');
return str.replace(
new RegExp(
`${escapeRegExp(UPPERCASE_PREFIX)}(.*?)${escapeRegExp(UPPERCASE_SUFFIX)}`,
'g'
),
(_, p1: string) => p1.toUpperCase()
);
}