Skip to content

Commit

Permalink
feat: poc grid layout drag-n-drop
Browse files Browse the repository at this point in the history
  • Loading branch information
KatoakDR committed Oct 22, 2023
1 parent 3ba64f4 commit 822e332
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 139 deletions.
5 changes: 5 additions & 0 deletions electron/renderer/components/grid-item/grid-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const GridItem: React.FC = (): JSX.Element => {
return <>TODO</>;
};

export { GridItem };
1 change: 1 addition & 0 deletions electron/renderer/components/grid-item/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './grid-item';
140 changes: 140 additions & 0 deletions electron/renderer/components/grid/grid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import {
EuiPanel,
EuiText,
useEuiOverflowScroll,
useEuiTheme,
} from '@elastic/eui';
import { cx } from '@emotion/css';
import { css } from '@emotion/react';
import Head from 'next/head';
import {
CSSProperties,
MouseEvent,
ReactNode,
TouchEvent,
forwardRef,
useMemo,
useRef,
useState,
} from 'react';
import { Responsive, WidthProvider } from 'react-grid-layout';
import { useLogger } from '../logger';

const Grid: React.FC = (): JSX.Element => {
const { logger } = useLogger('component:grid');

logger.info('rendering');

const { euiTheme } = useEuiTheme();

const gridLayoutStyles = css`
.react-grid-layout {
background: ${euiTheme.colors.lightestShade};
}
.react-grid-item {
padding: ${euiTheme.size.xs};
}
.react-grid-item.react-grid-placeholder {
background: ${euiTheme.colors.warning};
}
`;

const gridItemTextStyles = css`
font-family: ${euiTheme.font.familyCode};
white-space: pre-wrap;
${useEuiOverflowScroll('y', true)}
`;

/**
* Using hooks to save the layout state on change will cause the layouts to
* re-render because the layout component's value keeps changing every render.
* To avoid this we memoize the layout component using the `useMemo` hook.
* https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#react-hooks-performance
*/
const ResponsiveGridLayout = useMemo(() => {
return WidthProvider(Responsive);
}, []);

/**
* Define the initial layout state.
*/
const [layout, setLayout] = useState([
{ i: 'a', x: 0, y: 0, w: 3, h: 2 },
{ i: 'b', x: 3, y: 0, w: 3, h: 2 },
{ i: 'c', x: 6, y: 0, w: 3, h: 2 },
]);

/**
* To improve performance, we memoize the children prop so that it doesn't
* change between rerenders. And if the children don't change then the
* components within the layout won't rerender either.
* https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#performance
*/
const children = useMemo(() => {
return layout.map((item) => {
/**
* How to use custom components a react-grid-layout children.
* https://github.com/react-grid-layout/react-grid-layout/tree/master?tab=readme-ov-file#custom-child-components-and-draggable-handles
* https://stackoverflow.com/questions/67053157/react-grid-layout-error-draggablecore-not-mounted-on-dragstart
*/

interface ReactGridLayoutItemProps {
style?: CSSProperties;
className?: string;
onMouseDown?: (e: MouseEvent<HTMLDivElement>) => void;
onMouseUp?: (e: MouseEvent<HTMLDivElement>) => void;
onTouchEnd?: (e: TouchEvent<HTMLDivElement>) => void;
children?: ReactNode;
}

const MyGridItem = forwardRef<HTMLDivElement, ReactGridLayoutItemProps>(
(props, ref) => {
const { style, className, children, ...otherProps } = props;

return (
<EuiPanel
panelRef={ref}
hasBorder={true}
grow={false}
style={style}
className={cx(className)}
{...otherProps}
>
<EuiText css={gridItemTextStyles}>{item.i}</EuiText>
{children}
</EuiPanel>
);
}
);

MyGridItem.displayName = 'MyGridItem';

return <MyGridItem key={item.i} ref={useRef(null)} />;
});
}, [layout.length]);

return (
<>
<Head>
<link rel="stylesheet" href={`/react-grid/layout.min.css`} />
<link rel="stylesheet" href={`/react-grid/resizable.min.css`} />
</Head>
<ResponsiveGridLayout
css={gridLayoutStyles}
layouts={{ lg: layout }}
breakpoints={{ lg: 1200 }}
cols={{ lg: 30 }}
rowHeight={30}
isBounded={true}
isDraggable={true}
isDroppable={true}
isResizable={true}
resizeHandles={['se']}
>
{children}
</ResponsiveGridLayout>
</>
);
};

export { Grid };
1 change: 1 addition & 0 deletions electron/renderer/components/grid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './grid';
7 changes: 7 additions & 0 deletions electron/renderer/components/grid/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { css } from '@emotion/react';

export const styles = css`
#__next,
.example {
}
`;
145 changes: 6 additions & 139 deletions electron/renderer/pages/dnd.tsx
Original file line number Diff line number Diff line change
@@ -1,151 +1,18 @@
import Head from 'next/head';
import { useMemo, useState } from 'react';
import { Responsive, WidthProvider } from 'react-grid-layout';
import Link from 'next/link';
import { Grid } from '../components/grid/grid';
import { useLogger } from '../components/logger';

const DragDropPage: React.FC = (): JSX.Element => {
const { logger } = useLogger('page:dnd');

logger.info('rendering');

// https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#react-hooks-performance
const ResponsiveGridLayout = useMemo(() => {
return WidthProvider(Responsive);
}, []);

const [layout, setLayout] = useState([
{ i: 'a', x: 0, y: 0, w: 1, h: 2, static: true },
{ i: 'b', x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
{ i: 'c', x: 4, y: 0, w: 1, h: 2 },
]);

// https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#performance
const children = useMemo(() => {
logger.debug('generating children');
return layout.map((item) => <div key={item.i}>{item.i}</div>);
}, [layout.length]);

return (
<>
<Head>
<link rel="stylesheet" href={`/react-grid/layout.min.css`} />
<link rel="stylesheet" href={`/react-grid/resizable.min.css`} />
<style>
{`
body {
padding: 20px;
}
#content {
width: 100%;
}
.react-grid-layout {
background: #eee;
margin-top: 10px;
}
.layoutJSON {
background: #ddd;
border: 1px solid black;
margin-top: 10px;
padding: 10px;
}
.columns {
-moz-columns: 120px;
-webkit-columns: 120px;
columns: 120px;
}
.react-grid-item {
box-sizing: border-box;
}
.react-grid-item:not(.react-grid-placeholder) {
background: #ccc;
border: 1px solid black;
}
.react-grid-item.resizing {
opacity: 0.9;
}
.react-grid-item.static {
background: #cce;
}
.react-grid-item .text {
font-size: 24px;
text-align: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
height: 24px;
}
.react-grid-item .minMax {
font-size: 12px;
}
.react-grid-item .add {
cursor: pointer;
}
.react-grid-dragHandleExample {
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.toolbox {
background-color: #dfd;
width: 100%;
height: 120px;
overflow: scroll;
}
.hide-button {
cursor: pointer;
position: absolute;
font-size: 20px;
top: 0px;
right: 5px;
}
.toolbox__title {
font-size: 24px;
margin-bottom: 5px;
}
.toolbox__items {
display: block;
}
.toolbox__items__item {
display: inline-block;
text-align: center;
line-height: 40px;
cursor: pointer;
width: 40px;
height: 40px;
padding: 10px;
margin: 5px;
border: 1px solid black;
background-color: #ddd;
}
.droppable-element {
width: 150px;
text-align: center;
background: #fdd;
border: 1px solid black;
margin: 10px 0;
padding: 10px;
}
`}
</style>
</Head>
<div id="doug">Hello World</div>
<ResponsiveGridLayout
className="layout"
layouts={{ lg: layout }}
breakpoints={{ lg: 1200 }}
cols={{ lg: 12 }}
isBounded={true}
isDraggable={true}
isDroppable={true}
isResizable={true}
resizeHandles={['nw', 'ne', 'se', 'sw']}
>
{children}
</ResponsiveGridLayout>
<p>
<Link href="/">Go home</Link>
</p>
<Grid />
</>
);
};
Expand Down
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,14 @@
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"react/no-unknown-property": [
"error",
{
"ignore": [
"css"
]
}
]
}
}
Expand Down

0 comments on commit 822e332

Please sign in to comment.