Skip to content

Commit 7277e2d

Browse files
committed
Fix "double first letter" bug
...again 🥴
1 parent 5fc7a25 commit 7277e2d

File tree

3 files changed

+135
-109
lines changed

3 files changed

+135
-109
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webdevhome",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"private": true,
55
"scripts": {
66
"start": "react-scripts start",

src/App.tsx

+11-7
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,10 @@ function useCustomizeMode (): UseCustomizeModeReturn {
9898
}
9999
}, [mode])
100100

101-
function handleCustomizeAction (): void {
102-
toggleMode(AppMode.customize)
103-
}
101+
const handleCustomizeAction = useCallback(
102+
(): void => { toggleMode(AppMode.customize) },
103+
[]
104+
)
104105

105106
return { hiddenLinks, handleCustomizeAction }
106107
}
@@ -132,10 +133,13 @@ function useSearchMode (): UseSearchModeReturn {
132133
}
133134
}, [mode])
134135

135-
function handleSearchAction (): void {
136-
setLatestKeypress('')
137-
toggleMode(AppMode.search)
138-
}
136+
const handleSearchAction = useCallback(
137+
(): void => {
138+
setLatestKeypress('')
139+
toggleMode(AppMode.search)
140+
},
141+
[]
142+
)
139143

140144
return { handleSearchAction, latestKeypress }
141145
}

src/components/Search.tsx

+123-101
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import fuzzy from 'fuzzysort'
2-
import React, { ChangeEvent, Dispatch, FC, KeyboardEvent as ReactKeyboardEvent, memo, RefObject, SetStateAction, useEffect, useRef, useState } from 'react'
2+
import React, { ChangeEvent, Dispatch, FC, KeyboardEvent as ReactKeyboardEvent, memo, RefObject, SetStateAction, useEffect, useRef, useState, useCallback, useMemo } from 'react'
33
import { getAllLinks, LinkItem, SearchTarget } from '../links'
44
import { AppMode, setMode } from '../stores/currentModeStore'
55
import { useHiddenLinks } from '../stores/hiddenLinksStore'
@@ -27,121 +27,136 @@ export const Search: FC<SearchProps> = memo(({ latestKeypress }) => {
2727
}
2828
})
2929

30-
function handleInputChange (event: ChangeEvent<HTMLInputElement>): void {
31-
setSearchTerm(event.currentTarget.value)
32-
setKeyboardIndex(0)
33-
}
34-
35-
function handleInputKeyDown (event: ReactKeyboardEvent<HTMLInputElement>): void {
36-
switch (event.key) {
37-
case 'Backspace': {
38-
if (searchTerm !== '') { return }
30+
const handleInputChange = useCallback(
31+
(event: ChangeEvent<HTMLInputElement>): void => {
32+
setSearchTerm(event.currentTarget.value)
33+
setKeyboardIndex(0)
34+
},
35+
[setKeyboardIndex, setSearchTerm]
36+
)
3937

40-
if (searchTarget !== null) {
41-
setSearchTarget(null)
42-
} else {
43-
setMode(AppMode.default)
38+
const handleInputKeyDown = useCallback(
39+
(event: ReactKeyboardEvent<HTMLInputElement>): void => {
40+
switch (event.key) {
41+
case 'Backspace': {
42+
if (searchTerm !== '') { return }
43+
44+
if (searchTarget !== null) {
45+
setSearchTarget(null)
46+
} else {
47+
setMode(AppMode.default)
48+
}
49+
break
4450
}
45-
break
46-
}
4751

48-
case 'Tab': {
49-
event.preventDefault()
52+
case 'Tab': {
53+
event.preventDefault()
5054

51-
if (searchTarget !== null) { return }
52-
if (focusedResult === null) { return }
53-
if (focusedResult.obj.searchUrl === undefined) { return }
55+
if (searchTarget !== null) { return }
56+
if (focusedResult === null) { return }
57+
if (focusedResult.obj.searchUrl === undefined) { return }
5458

55-
setSearchTarget(focusedResult.obj as SearchTarget)
56-
setSearchTerm('')
57-
break
58-
}
59+
setSearchTarget(focusedResult.obj as SearchTarget)
60+
setSearchTerm('')
61+
break
62+
}
63+
64+
case 'Enter': {
65+
const url = getUrl(focusedResult?.obj ?? null, searchTarget, searchTerm)
5966

60-
case 'Enter': {
61-
const url = getUrl(focusedResult?.obj ?? null, searchTarget, searchTerm)
67+
if (url === null) { return }
6268

63-
if (url === null) { return }
69+
if (event.ctrlKey) {
70+
window.open(url, '', 'alwaysRaised=on')
71+
} else {
72+
window.location.href = url
73+
}
6474

65-
if (event.ctrlKey) {
66-
window.open(url, '', 'alwaysRaised=on')
67-
} else {
68-
window.location.href = url
75+
if (event.ctrlKey || event.shiftKey) { setMode(AppMode.default) }
76+
break
6977
}
7078

71-
if (event.ctrlKey || event.shiftKey) { setMode(AppMode.default) }
72-
break
73-
}
79+
case 'ArrowUp': {
80+
if (results === null) { return }
81+
event.preventDefault()
82+
setKeyboardIndex(Math.max(0, keyboardIndex - 1))
83+
break
84+
}
7485

75-
case 'ArrowUp': {
76-
if (results === null) { return }
77-
event.preventDefault()
78-
setKeyboardIndex(Math.max(0, keyboardIndex - 1))
79-
break
86+
case 'ArrowDown': {
87+
if (results === null) { return }
88+
event.preventDefault()
89+
setKeyboardIndex(Math.min(results.total - 1, keyboardIndex + 1))
90+
}
8091
}
92+
},
93+
[focusedResult, keyboardIndex, results, searchTarget, searchTerm, setKeyboardIndex, setSearchTarget, setSearchTerm]
94+
)
8195

82-
case 'ArrowDown': {
83-
if (results === null) { return }
84-
event.preventDefault()
85-
setKeyboardIndex(Math.min(results.total - 1, keyboardIndex + 1))
86-
}
87-
}
88-
}
96+
const handleGlobalKeyDown = useCallback(
97+
(event: KeyboardEvent): void => {
98+
if (event.key === 'Escape') {
99+
if (searchTarget !== null) {
100+
setSearchTarget(null)
101+
setSearchTerm('')
102+
return
103+
}
89104

90-
function handleGlobalKeyDown (event: KeyboardEvent): void {
91-
if (event.key === 'Escape') {
92-
if (searchTarget !== null) {
93-
setSearchTarget(null)
94-
setSearchTerm('')
95-
return
105+
setMode(AppMode.default)
96106
}
107+
},
108+
[searchTarget, setSearchTarget, setSearchTerm]
109+
)
97110

98-
setMode(AppMode.default)
99-
}
100-
}
101-
102-
const hints = <>
103-
<div className="search__results-hint">
111+
const hints = useMemo(
112+
() => <>
113+
<div className="search__results-hint">
104114
Type ahead to filter links.
105-
</div>
106-
<div className="search__results-hint">
107-
<kbd>Return</kbd>
108-
<div className="search__results-hint-description">
115+
</div>
116+
<div className="search__results-hint">
117+
<kbd>Return</kbd>
118+
<div className="search__results-hint-description">
109119
Open link
120+
</div>
110121
</div>
111-
</div>
112-
<div className="search__results-hint">
113-
<kbd>Ctrl</kbd> + <kbd>Return</kbd>
114-
<div className="search__results-hint-description">
122+
<div className="search__results-hint">
123+
<kbd>Ctrl</kbd> + <kbd>Return</kbd>
124+
<div className="search__results-hint-description">
115125
Open link in a new tab (background)
126+
</div>
116127
</div>
117-
</div>
118-
<div className="search__results-hint">
119-
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Return</kbd>
120-
<div className="search__results-hint-description">
128+
<div className="search__results-hint">
129+
<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Return</kbd>
130+
<div className="search__results-hint-description">
121131
Open link in a new tab (foreground)
132+
</div>
122133
</div>
123-
</div>
124-
</>
125-
126-
const resultElements = <>
127-
{results !== null && results.total > 0 ? (
128-
results.map(link => (
129-
<Link
130-
key={link.obj.url}
131-
title={link.obj.title}
132-
url={link.obj.url}
133-
icon={link.obj.icon}
134-
searchable={link.obj.searchUrl !== undefined}
135-
color={link.obj.color}
136-
customize={false}
137-
visible={true}
138-
focus={link === focusedResult}
139-
/>
140-
))
141-
) : (
142-
<div className="search__results-hint">No results found...</div>
143-
)}
144-
</>
134+
</>,
135+
[]
136+
)
137+
138+
const resultElements = useMemo(
139+
() => <>
140+
{results !== null && results.total > 0 ? (
141+
results.map(link => (
142+
<Link
143+
key={link.obj.url}
144+
title={link.obj.title}
145+
url={link.obj.url}
146+
icon={link.obj.icon}
147+
searchable={link.obj.searchUrl !== undefined}
148+
color={link.obj.color}
149+
customize={false}
150+
visible={true}
151+
focus={link === focusedResult}
152+
/>
153+
))
154+
) : (
155+
<div className="search__results-hint">No results found...</div>
156+
)}
157+
</>,
158+
[focusedResult, results]
159+
)
145160

146161
return (
147162
<div className="search">
@@ -193,19 +208,26 @@ function useSearch (latestKeypress: string): UseSearch {
193208
const { links } = useHiddenLinks()
194209
const visibleLinks = getAllLinks().filter(link => !links.includes(link.url))
195210

196-
const fuzzyOptions: Fuzzysort.KeyOptions = {
197-
key: 'title', allowTypo: false, limit: 6
198-
}
211+
const fuzzyOptions: Fuzzysort.KeyOptions = useMemo(
212+
() => ({ key: 'title', allowTypo: false, limit: 6 }),
213+
[]
214+
)
199215

200-
const results = searchTerm !== '' && searchTarget === null
201-
? fuzzy.go(searchTerm, visibleLinks, fuzzyOptions)
202-
: null
216+
const results = useMemo(
217+
() => searchTerm !== '' && searchTarget === null
218+
? fuzzy.go(searchTerm, visibleLinks, fuzzyOptions)
219+
: null,
220+
[fuzzyOptions, searchTarget, searchTerm, visibleLinks]
221+
)
203222

204-
const focusedResult = results?.[keyboardIndex] ?? null
223+
const focusedResult = useMemo(
224+
() => results?.[keyboardIndex] ?? null,
225+
[keyboardIndex, results]
226+
)
205227

206228
useEffect(() => {
207-
inputElement.current?.focus()
208229
setSearchTerm(latestKeypress)
230+
setTimeout(() => { inputElement.current?.focus() }, 0)
209231
}, [latestKeypress])
210232

211233
return {

0 commit comments

Comments
 (0)