@@ -6,6 +6,8 @@ import { Item, TodoCompletedList } from "./common";
66import { Form } from "./common/Todo/Form" ;
77import { TodoItem } from "./common/types" ;
88
9+ import uuid from "react-uuid" ;
10+
911export interface TodoAppProps {
1012 defaultItems ?: TodoItem [ ] ;
1113 onChange : ( items : TodoItem [ ] ) => void ;
@@ -15,29 +17,83 @@ function TodoApp(props: TodoAppProps) {
1517 const { defaultItems = [ ] , onChange } = props ;
1618 const [ items , setItems ] = useState < TodoItem [ ] > ( defaultItems ) ;
1719 const [ focus , setFocus ] = useState ( - 1 ) ;
18-
20+
1921 const setItemsCallback = ( updatedItems : TodoItem [ ] ) => {
2022 setItems ( updatedItems ) ;
2123 onChange ( updatedItems ) ;
2224 } ;
2325
24- const addItem = ( item : TodoItem | TodoItem [ ] ) => {
26+ const changeFocus = useCallback ( ( focusIndex : number ) => {
27+ setFocus ( focusIndex ) ;
28+ } , [ ] ) ;
29+
30+ const addItem = (
31+ item : TodoItem | TodoItem [ ] ,
32+ cursorLocation ?: number | null | undefined ,
33+ itemIndex ?: number
34+ ) => {
2535 const itemsCopy = [ ...items ] ;
26- if ( Array . isArray ( item ) ) {
27- item . forEach ( ( it ) => {
28- itemsCopy . unshift ( it ) ;
29- } ) ;
30- setItemsCallback ( [ ...itemsCopy ] ) ;
36+ //if we're typing in the "Add Item" input...
37+ if (
38+ typeof cursorLocation != "number" ||
39+ Array . isArray ( item ) ||
40+ itemIndex === undefined
41+ ) {
42+ if ( Array . isArray ( item ) ) {
43+ item . forEach ( ( it ) => {
44+ itemsCopy . unshift ( it ) ;
45+ } ) ;
46+ setItemsCallback ( [ ...itemsCopy ] ) ;
47+ } else {
48+ itemsCopy . unshift ( item ) ;
49+ setItemsCallback ( [ ...itemsCopy ] ) ;
50+ }
51+ return ;
52+ }
53+ // else if we are typing in any other input
54+ let charsAfterCursor = "" ;
55+ for ( let i = cursorLocation ; i < item . name . length ; i ++ ) {
56+ charsAfterCursor += item . name [ i ] ;
57+ }
58+ let charsBeforeCursor = "" ;
59+ for ( let i = 0 ; i < cursorLocation ; i ++ ) {
60+ charsBeforeCursor += item . name [ i ] ;
61+ }
62+ // do nothing if the field we are trying to Enter is blank
63+ if ( ! charsBeforeCursor && ! charsAfterCursor ) return ;
64+ // split up names based on where cursor is when user clicks Enter
65+ const beforeItem = {
66+ name : charsBeforeCursor ,
67+ uuid : uuid ( ) ,
68+ isComplete : false ,
69+ } ;
70+ const afterItem = {
71+ name : charsAfterCursor ,
72+ uuid : uuid ( ) ,
73+ isComplete : false ,
74+ } ;
75+ // insert both halves of the input into the itemsCopy array
76+ itemsCopy . splice ( itemIndex , 1 , beforeItem , afterItem ) ;
77+ // set items with updated array
78+ setItemsCallback ( [ ...itemsCopy ] ) ;
79+ // after enter is hit, re-position the cursor depending on where in the input it is
80+ if ( ! charsBeforeCursor ) {
81+ changeFocus ( itemsCopy . indexOf ( beforeItem ) ) ;
3182 } else {
32- itemsCopy . unshift ( item ) ;
33- setItemsCallback ( [ ...itemsCopy ] ) ;
83+ setTimeout ( ( ) => {
84+ const inputs = document . querySelectorAll ( "input[type='text']" ) ;
85+ const inputsArray = Array . from ( inputs ) ;
86+ const nextInputElement = inputsArray [
87+ itemsCopy . indexOf ( afterItem ) + 1
88+ ] as HTMLInputElement ;
89+ changeFocus ( itemsCopy . indexOf ( afterItem ) ) ;
90+ requestAnimationFrame ( ( ) => {
91+ nextInputElement . setSelectionRange ( 0 , 0 ) ;
92+ } ) ;
93+ } , 0 ) ;
3494 }
3595 } ;
3696
37- const changeFocus = useCallback ( ( focusIndex : number ) => {
38- setFocus ( focusIndex ) ;
39- } , [ ] )
40-
4197 const completedItems = items . filter ( ( item : TodoItem ) => item . isComplete ) ;
4298 const todoItems = items . filter ( ( item : TodoItem ) => ! item . isComplete ) ;
4399
@@ -77,7 +133,7 @@ function TodoApp(props: TodoAppProps) {
77133 ) ;
78134 } ) }
79135 </ Reorder . Group >
80- < TodoCompletedList
136+ < TodoCompletedList
81137 items = { items }
82138 setItemsCallback = { setItemsCallback }
83139 completedItems = { completedItems }
0 commit comments