From 1d709b33a739a5dff6ca356e8842d6355ed31f93 Mon Sep 17 00:00:00 2001 From: Jayesh Deorukhkar Date: Tue, 25 Oct 2022 20:03:23 +0530 Subject: [PATCH 1/2] feat: handled backspace at the start of todo item --- .../Todo/common/Todo/Item/index.tsx | 145 +++++++++++++----- 1 file changed, 103 insertions(+), 42 deletions(-) diff --git a/src/components/Todo/common/Todo/Item/index.tsx b/src/components/Todo/common/Todo/Item/index.tsx index bba9596..e40ce19 100644 --- a/src/components/Todo/common/Todo/Item/index.tsx +++ b/src/components/Todo/common/Todo/Item/index.tsx @@ -1,4 +1,10 @@ -import React, { FC, useEffect, useRef, useState } from 'react'; +import React, { + FC, + KeyboardEventHandler, + useEffect, + useRef, + useState, +} from "react"; import uuid from 'react-uuid'; import { @@ -76,6 +82,100 @@ export const Item: FC = ({ setItemText(items[itemIndex].name); }, []); + useEffect(() => { + setItemText(items[itemIndex].name); + }, [items[itemIndex].name]); + + const handleDelete = () => { + items.splice(itemIndex, 1); + setItemsCallback([...items]); + }; + + const getNthTodoElement = (n: number) => { + return ( + document.querySelector( + `.${classes.reorderItem}:has(${classes.textFeild}):nth-of-type(${ + n + 1 + }) .${classes.textFeild} input` + ) ?? + document.querySelectorAll( + `.${classes.textFeild} input` + )[n] + ); + }; + + const handleBackspace = () => { + if (!itemIndex) return; // Do nothing, for first TODO + + if (inputRef.current!.selectionStart) return; // Do nothing if cursor isn't at start. + + let previousItemElement = getNthTodoElement(itemIndex - 1); + + const previousItem = items.at(itemIndex - 1)!; + const previousItemName = previousItem.name; + + if (itemText) { + previousItem.name = `${previousItemName}${previousItemName ? " " : ""}${itemText}`; + } + + previousItemElement.focus(); + + // Focusing the element takes a bit time, so if selection is set synchronously the selection is unset. + setTimeout(() => { + // Set the cursor position just before the current item name + const cursorPos = previousItemName?.length! + Number(!!previousItemName); + previousItemElement.setSelectionRange(cursorPos, cursorPos); + }, 0); + + handleDelete(); + return true; + }; + + const handleKeyDown: KeyboardEventHandler = (e) => { + switch (e.key) { + case "Enter": { + if (itemIndex < 1) + addItem({ name: "", uuid: uuid(), isComplete: false }); + break; + } + + case "Backspace": { + if (handleBackspace()) e.preventDefault(); + break; + } + } + handleArrowKey(e) + }; + + const handleArrowKey : KeyboardEventHandler = (e) => { + const inputs = document.querySelectorAll("input[type='text']"); + const inputsArray = Array.from(inputs); + const index = inputsArray.indexOf( + inputRef.current as HTMLInputElement + ); + + if (inputRef.current) { + if (e.key === 'ArrowUp') { + // Move cursor to the previous item + // Checks if the focused item is at the top + if (index >= 0) { + const nextInputElement = inputsArray[ + index - 1 + ] as HTMLInputElement; + nextInputElement.focus(); + } + } else if (e.key === 'ArrowDown') { + // Move cursor to the next item + // Checks if the focused item is at the bottom + if (index < inputsArray.length - 1) { + const nextInputElement = inputsArray[ + index + 1 + ] as HTMLInputElement; + nextInputElement.focus(); + } + } + } + } if (!items[itemIndex].isComplete) { return ( = ({ onBlur={() => { setItemsCallback([...items]); }} - onKeyPress={(e) => - e.key === 'Enter' && - itemIndex < 1 && - addItem({ name: '', uuid: uuid(), isComplete: false }) - } - onKeyDown={(e) => { - const inputs = document.querySelectorAll("input[type='text']"); - const inputsArray = Array.from(inputs); - const index = inputsArray.indexOf( - inputRef.current as HTMLInputElement - ); - - if (inputRef.current) { - if (e.key === 'ArrowUp') { - // Move cursor to the previous item - // Checks if the focused item is at the top - if (index >= 0) { - const nextInputElement = inputsArray[ - index - 1 - ] as HTMLInputElement; - nextInputElement.focus(); - } - } else if (e.key === 'ArrowDown') { - // Move cursor to the next item - // Checks if the focused item is at the bottom - if (index < inputsArray.length - 1) { - const nextInputElement = inputsArray[ - index + 1 - ] as HTMLInputElement; - nextInputElement.focus(); - } - } - } - }} + onKeyDown={handleKeyDown} /> - { - items.splice(itemIndex, 1); - setItemsCallback([...items]); - }} - /> + ); From 210390b8ae811f23bd0a3b3aca227983f238bef4 Mon Sep 17 00:00:00 2001 From: Jayesh Deorukhkar Date: Tue, 25 Oct 2022 20:16:52 +0530 Subject: [PATCH 2/2] feat: handled backspace at the start of todo item --- .../Todo/common/Todo/Item/index.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/Todo/common/Todo/Item/index.tsx b/src/components/Todo/common/Todo/Item/index.tsx index bf51867..a1d8554 100644 --- a/src/components/Todo/common/Todo/Item/index.tsx +++ b/src/components/Todo/common/Todo/Item/index.tsx @@ -137,17 +137,8 @@ export const Item: FC = ({ }; const handleKeyDown: KeyboardEventHandler = (e) => { - switch (e.key) { - case "Enter": { - if (itemIndex < 1) - addItem({ name: "", uuid: uuid(), isComplete: false }); - break; - } - - case "Backspace": { + if (e.key === 'Backspace') { if (handleBackspace()) e.preventDefault(); - break; - } } handleArrowKey(e) }; @@ -236,6 +227,14 @@ export const Item: FC = ({ onBlur={() => { setItemsCallback([...items]); }} + onKeyPress={ + (e) => { + e.key === "Enter" && + itemIndex < 1 && + addItem({ name: "", uuid: uuid(), isComplete: false }) + changeFocus(-1) + } + } onKeyDown={handleKeyDown} />