Refactor/inplace input (#541)

* wip

* Changed all other components

* Removed console log

* Console.log

* lint

* Removed internal state

* Fix

* Lint
This commit is contained in:
Lucas Bordeau
2023-07-09 01:45:52 +02:00
committed by GitHub
parent b3d0061e0d
commit e03d5ed8a7
47 changed files with 680 additions and 326 deletions

View File

@ -0,0 +1,55 @@
import styled from '@emotion/styled';
import { DropResult } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
export const StyledBoard = styled.div`
border-radius: ${({ theme }) => theme.spacing(2)};
display: flex;
flex-direction: row;
height: calc(100%);
overflow-x: auto;
width: 100%;
`;
export type Column = {
id: string;
title: string;
colorCode?: string;
itemKeys: string[];
};
export function getOptimisticlyUpdatedBoard(
board: Column[],
result: DropResult,
) {
const newBoard = JSON.parse(JSON.stringify(board));
const { destination, source } = result;
if (!destination) return;
const sourceColumnIndex = newBoard.findIndex(
(column: Column) => column.id === source.droppableId,
);
const sourceColumn = newBoard[sourceColumnIndex];
const destinationColumnIndex = newBoard.findIndex(
(column: Column) => column.id === destination.droppableId,
);
const destinationColumn = newBoard[destinationColumnIndex];
if (!destinationColumn || !sourceColumn) return;
const sourceItems = sourceColumn.itemKeys;
const destinationItems = destinationColumn.itemKeys;
const [removed] = sourceItems.splice(source.index, 1);
destinationItems.splice(destination.index, 0, removed);
const newSourceColumn = {
...sourceColumn,
itemKeys: sourceItems,
};
const newDestinationColumn = {
...destinationColumn,
itemKeys: destinationItems,
};
newBoard.splice(sourceColumnIndex, 1, newSourceColumn);
newBoard.splice(destinationColumnIndex, 1, newDestinationColumn);
return newBoard;
}

View File

@ -0,0 +1,36 @@
import React from 'react';
import styled from '@emotion/styled';
export const StyledColumn = styled.div`
background-color: ${({ theme }) => theme.background.primary};
display: flex;
flex-direction: column;
min-width: 200px;
padding: ${({ theme }) => theme.spacing(2)};
`;
export const StyledColumnTitle = styled.h3`
color: ${({ color }) => color};
font-family: 'Inter';
font-size: ${({ theme }) => theme.font.size.md};
font-style: normal;
font-weight: ${({ theme }) => theme.font.weight.medium};
line-height: ${({ theme }) => theme.text.lineHeight};
margin: 0;
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
type OwnProps = {
colorCode?: string;
title: string;
children: React.ReactNode;
};
export function BoardColumn({ colorCode, title, children }: OwnProps) {
return (
<StyledColumn>
<StyledColumnTitle color={colorCode}> {title}</StyledColumnTitle>
{children}
</StyledColumn>
);
}

View File

@ -0,0 +1,37 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconPlus } from '@/ui/icons/index';
const StyledButton = styled.button`
align-items: center;
align-self: baseline;
background-color: ${({ theme }) => theme.background.primary};
border: none;
border-radius: ${({ theme }) => theme.border.radius.md};
color: ${({ theme }) => theme.font.color.tertiary};
cursor: pointer;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
justify-content: center;
padding: ${({ theme }) => theme.spacing(1)};
&:hover {
background-color: ${({ theme }) => theme.background.secondary};
}
`;
type OwnProps = {
onClick: () => void;
};
export function NewButton({ onClick }: OwnProps) {
const theme = useTheme();
return (
<StyledButton onClick={onClick}>
<IconPlus size={theme.icon.size.md} />
New
</StyledButton>
);
}

View File

@ -0,0 +1,55 @@
import { DropResult } from '@hello-pangea/dnd';
import { getOptimisticlyUpdatedBoard } from '../Board';
describe('getOptimisticlyUpdatedBoard', () => {
it('should return a new board with the updated cell', () => {
const initialColumn1: string[] = ['item-1', 'item-2', 'item-3'];
const initialColumn2: string[] = ['item-4', 'item-5'];
const finalColumn1: string[] = ['item-2', 'item-3'];
const finalColumn2: string[] = ['item-4', 'item-1', 'item-5'];
const dropResult = {
source: {
droppableId: 'column-1',
index: 0,
},
destination: {
droppableId: 'column-2',
index: 1,
},
} as DropResult;
const initialBoard = [
{
id: 'column-1',
title: 'My Column',
itemKeys: initialColumn1,
},
{
id: 'column-2',
title: 'My Column',
itemKeys: initialColumn2,
},
];
const updatedBoard = getOptimisticlyUpdatedBoard(initialBoard, dropResult);
const finalBoard = [
{
id: 'column-1',
title: 'My Column',
itemKeys: finalColumn1,
},
{
id: 'column-2',
title: 'My Column',
itemKeys: finalColumn2,
},
];
expect(updatedBoard).toEqual(finalBoard);
expect(updatedBoard).not.toBe(initialBoard);
});
});