Skip to content

Commit

Permalink
feat(ui): highlight with keyboard and mouse logic
Browse files Browse the repository at this point in the history
  • Loading branch information
stdword committed Nov 3, 2023
1 parent 766ab05 commit bb2b1f1
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 42 deletions.
10 changes: 5 additions & 5 deletions src/ui/insert.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ div {
border-radius: 8px;

transition-timing-function: ease-out;
transition-duration: .3s;
transition-duration: .15s;
transition-property: all;

opacity: 0; /* will be set at runtime */
Expand Down Expand Up @@ -149,7 +149,7 @@ div {
position: relative;
}

.item > a {
.item {
word-break: break-all;

background: 0 0;
Expand Down Expand Up @@ -183,16 +183,16 @@ div {
text-decoration: none;
}

.item > a > span {
.item > span {
flex: 1 1 0%;
}

.item-selected, .item:hover {
.selected {
word-break: break-all;
background-color: var(--ls-a-chosen-bg);
}

.item-selected span, .item:hover span {
.selected span{
color: var(--ls-secondary-text-color);
}

Expand Down
145 changes: 108 additions & 37 deletions src/ui/insert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ function InsertUI({ blockUUID }) {
const [visible, setVisible] = useState(true)
const [searchQueryState, setSearchQueryState] = useState('')
const [resultsState, setResultsState] = useState([] as string[])
const [highlightedResultState, setHighlightedResultState] = useState(null)
const [highlightedIndexState, setHighlightedIndexState] = useState(null as number | null)
// const firstUpdate = useRef(true)

function showUI() {
// handle show/hide animation
Expand Down Expand Up @@ -51,54 +52,126 @@ function InsertUI({ blockUUID }) {
}

useEffect(() => {
console.log('on:SHOW', visible)

if (visible)
setTimeout(showUI, 100)
}, [visible])

useEffect(() => {
console.log('on:INIT')

logseq.on('ui:visible:changed', ({ visible }) => {
if (visible)
setVisible(true)
})
}, [])

useEffect(() => {
console.log('on:KEYUP')
const saveInputValue = (event) => {
const input = event.target! as HTMLInputElement
setSearchQueryState(input.value)
}

const handleKeyup = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
if (searchQueryState !== '') {
setSearchQueryState('')
return
}
const returnFocus = (event: FocusEvent) => {
const input = event.target! as HTMLInputElement
input.focus()
}

hideUI()
const actWithHighlightedItem = (event: KeyboardEvent) => {
if (event.key === 'ArrowDown') {
event.preventDefault()
if (highlightedIndexState === null) {
setHighlightedIndexState(0)
return
}
const maxIndex = resultsState.length - 1
if (highlightedIndexState === maxIndex)
return
setHighlightedIndexState(highlightedIndexState + 1)
}
else if (event.key === 'ArrowUp') {
event.preventDefault()
if (highlightedIndexState === null) {
if (resultsState.length > 0)
setHighlightedIndexState(resultsState.length - 1)
return
}
const minIndex = 0
if (highlightedIndexState === minIndex)
return
setHighlightedIndexState(highlightedIndexState - 1)
}
else if (event.key === 'Enter') {
event.preventDefault()
insertHighlightedItem()
}
}

document.addEventListener('keyup', handleKeyup, false)
const handleEscapeKey = (event: KeyboardEvent) => {
const input = event.target! as HTMLInputElement
if (event.key === 'Escape') {
if (input.value !== '') {
setSearchQueryState('')
return
}

return () => {
document.removeEventListener('keyup', handleKeyup)
hideUI()
return
}
}, [searchQueryState])
}

// filter results
useEffect(() => {
console.log('on:FILTER', searchQueryState)
let results = ['test template', 'some template', 'cool', 'words', 'And long template names', 'with upper LETTERS']
let results = [
'test template', 'some template', 'cool', 'words', 'And long template names', 'with upper LETTERS',
'test template', 'some template', 'cool', 'words', 'And long template names', 'with upper LETTERS',
'test template', 'some template', 'cool', 'words', 'And long template names', 'with upper LETTERS',
]
if (searchQueryState)
results = results.filter(
(result) => result.toLowerCase().includes(searchQueryState.toLowerCase())
)

setResultsState(results)
updateHighlightFor(results)
}, [searchQueryState])

function updateHighlightFor(results) {
if (results.length == 0) {
setHighlightedIndexState(null)
return
}

if (highlightedIndexState === null)
setHighlightedIndexState(0)
else
if (highlightedIndexState >= results.length)
setHighlightedIndexState(results.length - 1)
}

useEffect(() => {
const itemsElement = document.getElementById('items')!
resultsState.forEach((item, index) => {
const div = itemsElement.childNodes[index] as HTMLDivElement
if (highlightedIndexState === null || index !== highlightedIndexState)
div.classList.remove('selected')
else
div.classList.add('selected')
})
}, [highlightedIndexState])

const highlightItem = (event: MouseEvent) => {
const currentItem = (event.target! as HTMLDivElement).closest('.item')
const itemsElement = document.getElementById('items')!
for (const [index, node] of Object.entries(itemsElement.childNodes)) {
if (node === currentItem) {
setHighlightedIndexState(Number(index))
break
}
}
}

const insertHighlightedItem = () => {
if (highlightedIndexState !== null)
console.log('INSERT', resultsState[highlightedIndexState])
}

return (
<div id="modal">
Expand All @@ -112,31 +185,29 @@ function InsertUI({ blockUUID }) {
type="text"
placeholder=" 🏛️ Search for a template or view..."
value={searchQueryState}
onInput={(event) => {
const input = event.target! as HTMLInputElement
setSearchQueryState(input.value)
}}
onfocusout={(event) => {
const input = event.target! as HTMLInputElement
input.focus()
}}
onKeyDown={actWithHighlightedItem}
onKeyUp={handleEscapeKey}
onInput={saveInputValue}
onfocusout={returnFocus}
/>
</div>
<div id="results-wrap">
<div id="results">
<div id="items">
{resultsState.map((item) => (
<div className="item" /* onClick={insertBlocks} */>
<a>
<span>
<div className="cell">
<span className="cell-left">{item}</span>
<div className="cell-right">
<code className="label">Template</code>
</div>
<div className="item"
onClick={insertHighlightedItem}
onMouseDown={highlightItem}
onMouseEnter={highlightItem}
>
<span>
<div className="cell">
<span className="cell-left">{item}</span>
<div className="cell-right">
<code className="label">Template</code>
</div>
</span>
</a>
</div>
</span>
</div>
))}
</div>
Expand Down

0 comments on commit bb2b1f1

Please sign in to comment.