Skip to content

Commit

Permalink
Merge pull request #17 from githubocto/aw/edit-add-data
Browse files Browse the repository at this point in the history
edit part II: Add ability to add & delete column/rows
  • Loading branch information
Amelia Wattenberger authored Jan 20, 2022
2 parents 75ac3ce + 11ee519 commit 21c26d8
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 53 deletions.
11 changes: 9 additions & 2 deletions src/components/cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ interface CellProps {
status?: string;
isNearRightEdge?: boolean;
isNearBottomEdge?: boolean;
isFirstColumn?: boolean;
isFirstColumn: boolean;
isExtraBlankRow: boolean;
hasStatusIndicator?: boolean;
background?: string;
isEditable: boolean;
onCellChange?: (value: any) => void;
onRowDelete?: () => void;
isFocused: boolean;
onFocusChange: (value: [number, number] | null) => void;
onMouseEnter?: Function;
Expand All @@ -35,10 +37,12 @@ export const Cell = React.memo(function (props: CellProps) {
categoryColor,
status,
isFirstColumn,
isExtraBlankRow,
isNearRightEdge,
isNearBottomEdge,
isEditable,
onCellChange,
onRowDelete,
isFocused,
onFocusChange,
background,
Expand Down Expand Up @@ -114,9 +118,12 @@ export const Cell = React.memo(function (props: CellProps) {
<EditableCell
value={rawValue}
isEditable={isEditable}
isFirstColumn={isFirstColumn}
onChange={onCellChange}
isFocused={isFocused}
onFocusChange={onFocusChange}>
isExtraBlankRow={isExtraBlankRow}
onFocusChange={onFocusChange}
onRowDelete={onRowDelete}>
<div
css={[
tw`w-full h-full flex flex-none items-center px-4`,
Expand Down
65 changes: 46 additions & 19 deletions src/components/editable-cell.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TrashIcon } from '@primer/octicons-react';
import React, { useEffect } from 'react';
import { areEqual } from 'react-window';
import tw from 'twin.macro';
Expand All @@ -6,37 +7,44 @@ interface EditableCellProps {
value: any;
isEditable: boolean;
onChange?: (value: any) => void;
isFirstColumn: boolean;
isFocused: boolean;
isExtraBlankRow: boolean;
onFocusChange?: (value: [number, number] | null) => void;
onRowDelete?: () => void;
children: any;
}
export const EditableCell = React.memo(function (props: EditableCellProps) {
const {
value,
isFirstColumn,
isEditable,
onChange,
isFocused,
isExtraBlankRow,
onFocusChange,
onRowDelete,
children,
} = props;

const [isEditing, setIsEditing] = React.useState(false);
const isEditingRef = React.useRef(isEditing);
const hasSubmittedFormRef = React.useRef(false);
const buttonElement = React.useRef<HTMLButtonElement>(null);
const [editedValue, setEditedValue] = React.useState(value);
const [editedValue, setEditedValue] = React.useState(value || "");

useEffect(() => {
setEditedValue(value);
setEditedValue(value || "");
}, [value]);
useEffect(() => {
isEditingRef.current = isEditing;
}, [isEditing]);

const onSubmit = () => {
onFocusChange?.([1, 0]);
onChange?.(editedValue);
hasSubmittedFormRef.current = true;
onChange?.(editedValue);
setIsEditing(false);
onFocusChange?.([1, 0]);
}

useEffect(() => {
Expand All @@ -62,6 +70,9 @@ export const EditableCell = React.memo(function (props: EditableCellProps) {
e.stopPropagation()
e.preventDefault()
} else if (e.key === 'Enter' && !isEditingRef.current) {
// don't focus when triggering delete
// @ts-ignore
if (e.target?.classList.contains('delete-button')) return
setTimeout(() => {
// without the timeout, the form submits immediately
setIsEditing(true);
Expand All @@ -87,7 +98,8 @@ export const EditableCell = React.memo(function (props: EditableCellProps) {
onSubmit();
}}
css={[
tw`w-full h-full border-[3px] border-transparent border-indigo-500`,
tw`w-full h-full border-[3px] border-transparent`,
isExtraBlankRow ? `border-gray-300` : `border-indigo-500`,
]}>
<input
type="text"
Expand All @@ -98,7 +110,7 @@ export const EditableCell = React.memo(function (props: EditableCellProps) {
css={[
tw`w-full h-full py-2 px-4 font-mono text-sm focus:outline-none bg-transparent`,
]}
value={editedValue}
value={editedValue || ""}
onChange={e => setEditedValue(e.target.value)}
onKeyDown={e => {
if (e.key === 'Escape') {
Expand All @@ -115,19 +127,34 @@ export const EditableCell = React.memo(function (props: EditableCellProps) {
/>
</form>
) : (
<button
ref={buttonElement}
css={[
tw`w-full h-full flex items-center cursor-cell border-[3px] border-transparent focus:outline-none`,
isFocused && tw`border-indigo-500`,
]}
onFocus={() => onFocusChange?.([0, 0])}
onClick={() => onFocusChange?.([0, 0])}
onDoubleClick={() => setIsEditing(true)}
>
{children}
</button>

<div css={[
tw`w-full h-full`,
]}>
{isFirstColumn && (
<button
css={[tw`absolute h-full text-red-500! opacity-0 group-hover:opacity-100 focus:opacity-100`]}
className="delete-button"
onClick={e => {
e.stopPropagation();
e.preventDefault();
onRowDelete?.();
}}>
<TrashIcon />
</button>
)}
<button
ref={buttonElement}
css={[
tw`w-full h-full flex items-center cursor-cell border-[3px] border-transparent focus:outline-none`,
isFocused && (isExtraBlankRow ? tw`border-gray-300` : tw`border-indigo-500`),
]}
onFocus={() => onFocusChange?.([0, 0])}
onClick={() => onFocusChange?.([0, 0])}
onDoubleClick={() => setIsEditing(true)}
>
{children}
</button>
</div>
);
}, areEqual);

Expand Down
Loading

0 comments on commit 21c26d8

Please sign in to comment.