add grid bg and use react-resize-detector

This commit is contained in:
Bowen Tan 2021-10-12 11:42:50 +08:00
parent 522c85bc2a
commit eceec4b4c6
6 changed files with 113 additions and 94 deletions

View File

@ -1,7 +1,7 @@
import { useMemo, useState } from 'react';
import { GridCallbacks } from '@meta-ui/runtime';
import { Box } from '@chakra-ui/react';
import { css } from '@emotion/react';
import produce from 'immer';
import { App } from '../metaUI';
import { StructureTree } from './StructureTree';
import {
@ -15,7 +15,6 @@ import { useAppModel } from '../operations/useAppModel';
import { KeyboardEventWrapper } from './KeyboardEventWrapper';
import { genComponentWrapper } from './ComponentWrapper';
let count = 0;
export const Editor = () => {
const [selectedComponentId, setSelectedComponentId] = useState('');
const [hoverComponentId, setHoverComponentId] = useState('');
@ -47,55 +46,38 @@ export const Editor = () => {
setHoverComponentId,
]);
// const Wrapper: React.FC<{ id: string }> = useMemo(() => {
// return props => {
// const style = css`
// height: 100%;
// box-shadow: 0 0 ${props.id === selectedComponentId ? 1 : 0}px red;
// `;
// const onClick = (e: React.MouseEvent<HTMLElement>) => {
// e.stopPropagation();
// setSelectedComponentId(() => props.id);
// };
// return (
// <div onClick={onClick} css={style}>
// {props.children}
// </div>
// );
// };
// }, [selectedComponentId]);
const gridCallbacks: GridCallbacks = useMemo(() => {
return {
onDragStop(id, layout) {
console.log('dragstop');
eventBus.send(
'operation',
new ModifyComponentPropertyOperation(id, 'layout', layout)
);
},
onDrop(id, layout, _, e) {
const component = e.dataTransfer?.getData('component') || '';
const componentId = `component${layout.length++}`;
eventBus.send(
'operation',
new CreateComponentOperation(id, 'container', component, componentId)
);
const gridCallbacks: GridCallbacks = {
onDragStop(id, layout) {
console.log('dragstop');
eventBus.send(
'operation',
new ModifyComponentPropertyOperation(id, 'layout', layout)
);
},
onDrop(id, layout, item, e) {
const component = e.dataTransfer?.getData('component') || '';
const componentId = `component${count++}`;
eventBus.send(
'operation',
new CreateComponentOperation(id, 'container', component, componentId)
);
const newLayout = produce(layout, draft => {
draft.forEach(l => {
if (l.i === '__dropping-elem__') {
l.i = componentId;
}
});
}).filter(v => !!v); // there is unknown empty in array
const newLayout = [
...layout,
{
...item,
w: 3,
i: componentId,
},
];
eventBus.send(
'operation',
new ModifyComponentPropertyOperation(id, 'layout', newLayout)
);
},
};
eventBus.send(
'operation',
new ModifyComponentPropertyOperation(id, 'layout', newLayout)
);
},
};
}, []);
return (
<KeyboardEventWrapper selectedComponentId={selectedComponentId}>

View File

@ -2,7 +2,11 @@ import { ChakraProvider } from '@chakra-ui/react';
import { css } from '@emotion/react';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { Editor } from './components/Editor';
export default function renderApp() {
ReactDOM.render(
<StrictMode>

View File

@ -34,6 +34,7 @@
"react-dom": "^17.0.0",
"react-grid-layout": "^1.3.0",
"react-markdown": "^6.0.2",
"react-resize-detector": "^6.7.6",
"react-simple-code-editor": "^0.11.0",
"wouter": "^2.7.4"
},

View File

@ -1,41 +1,41 @@
import RGL, { WidthProvider } from 'react-grid-layout';
import { Static, Type } from '@sinclair/typebox';
import RGL from 'react-grid-layout';
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';
const ReactGridLayout = WidthProvider(RGL);
const GridLayout: React.FC<ReactGridLayout.ReactGridLayoutProps> = props => {
const { children } = props;
const spacing = 10;
const { width, ref } = useResizeDetector();
export const LayoutPropertySchema = Type.Array(
Type.Object({
x: Type.Number(),
y: Type.Number(),
w: Type.Number(),
h: Type.Number(),
i: Type.String(),
isResizable: Type.Optional(Type.Boolean()),
})
);
const bgCss = css`
height: 100%;
background: white;
background-image: linear-gradient(#eee 1px, transparent 0),
linear-gradient(90deg, #eee 1px, transparent 0);
background-size: ${(width || 0) / 12}px ${GRID_HEIGHT + spacing}px;
background-position: 0px ${spacing / 2}px;
`;
const GridLayout: React.FC<{
layout: Static<typeof LayoutPropertySchema>;
onDragStop?: (layout: RGL.Layout[]) => void;
onDrop?: (layout: RGL.Layout[], item: RGL.Layout, event: DragEvent) => void;
}> = ({ children, layout, onDragStop, onDrop }) => {
return (
<ReactGridLayout
isDraggable={!!onDragStop}
isResizable={!!onDragStop}
compactType={null}
preventCollision={true}
rowHeight={GRID_HEIGHT}
layout={layout}
onDragStop={onDragStop}
onDrop={onDrop}
isDroppable={true}
>
{children}
</ReactGridLayout>
<div ref={ref} css={bgCss}>
<RGL
cols={12}
// isDraggable={!!onDragStop}
// isResizable={!!onDragStop}
compactType={null}
preventCollision={true}
rowHeight={GRID_HEIGHT}
width={width || 0}
margin={[spacing, spacing]}
isDroppable={true}
{...props}
>
{children}
</RGL>
</div>
);
};

View File

@ -1,10 +1,9 @@
import React, { Suspense } from 'react';
import RGL from 'react-grid-layout';
import { ComponentImplementation } from '../../services/registry';
import { createComponent } from '@meta-ui/core';
import { getSlots } from '../_internal/Slot';
import { LayoutPropertySchema } from '../../components/_internal/GridLayout';
import { Static, Type } from '@sinclair/typebox';
import { partial } from 'lodash';
const BaseGridLayout = React.lazy(() => import('../../components/_internal/GridLayout'));
@ -14,25 +13,33 @@ const GridLayout: ComponentImplementation<Static<typeof PropsSchema>> = ({
gridCallbacks,
component,
}) => {
const onDragStop = (layout: RGL.Layout[]) => {
gridCallbacks?.onDragStop && gridCallbacks?.onDragStop(component.id, layout);
};
const onDrop = (layout: RGL.Layout[], item: RGL.Layout, e: DragEvent) => {
gridCallbacks?.onDrop && gridCallbacks?.onDrop(component.id, layout, item, e);
};
const onDragStop = gridCallbacks?.onDragStop
? partial(gridCallbacks.onDragStop, component.id)
: undefined;
const onDrop = gridCallbacks?.onDrop
? partial(gridCallbacks.onDrop, component.id)
: undefined;
return (
<Suspense fallback={null}>
<div style={{ boxShadow: '0 0 1px red' }}>
<BaseGridLayout onDragStop={onDragStop} onDrop={onDrop} layout={layout}>
{getSlots(slotsMap, 'container')}
</BaseGridLayout>
</div>
<BaseGridLayout onDragStop={onDragStop} onDrop={onDrop} layout={layout}>
{getSlots(slotsMap, 'container')}
</BaseGridLayout>
</Suspense>
);
};
const PropsSchema = Type.Object({
layout: LayoutPropertySchema,
layout: Type.Array(
Type.Object({
x: Type.Number(),
y: Type.Number(),
w: Type.Number(),
h: Type.Number(),
i: Type.String(),
isResizable: Type.Optional(Type.Boolean()),
})
),
});
export default {

View File

@ -3016,6 +3016,11 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/resize-observer-browser@^0.1.6":
version "0.1.6"
resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.6.tgz#d8e6c2f830e2650dc06fe74464472ff64b54a302"
integrity sha512-61IfTac0s9jvNtBCpyo86QeaN8qqpMGHdK0uGKCCIy2dt5/Yk84VduHIdWAcmkC5QvdkPL0p5eWYgUZtHKKUVg==
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
@ -6379,6 +6384,11 @@ lodash.templatesettings@^4.0.0:
dependencies:
lodash._reinterpolate "^3.0.0"
lodash.throttle@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
lodash.truncate@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
@ -7684,6 +7694,16 @@ react-resizable@^3.0.4:
prop-types "15.x"
react-draggable "^4.0.3"
react-resize-detector@^6.7.6:
version "6.7.6"
resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-6.7.6.tgz#4416994e5ead7eba76606e3a248a1dfca49b67a3"
integrity sha512-/6RZlul1yePSoYJxWxmmgjO320moeLC/khrwpEVIL+D2EjLKhqOwzFv+H8laMbImVj7Zu4FlMa0oA7au3/ChjQ==
dependencies:
"@types/resize-observer-browser" "^0.1.6"
lodash.debounce "^4.0.8"
lodash.throttle "^4.1.1"
resize-observer-polyfill "^1.5.1"
react-simple-code-editor@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/react-simple-code-editor/-/react-simple-code-editor-0.11.0.tgz#bb57c7c29b570f2ab229872599eac184f5bc673c"
@ -7952,6 +7972,11 @@ require-from-string@^2.0.2:
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"