fix: add arrows navigation for tag hint

This commit is contained in:
Antonella Sgarlatta
2021-06-03 20:46:44 -03:00
parent 622cca770f
commit a9f0c6fd2f
4 changed files with 63 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
import { AppState } from '@/ui_models/app_state'; import { AppState } from '@/ui_models/app_state';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { useRef, useEffect } from 'preact/hooks';
import { Icon } from './Icon'; import { Icon } from './Icon';
type Props = { type Props = {
@@ -9,6 +10,10 @@ type Props = {
export const AutocompleteTagHint = observer( export const AutocompleteTagHint = observer(
({ appState, closeOnBlur }: Props) => { ({ appState, closeOnBlur }: Props) => {
const { autocompleteTagHintFocused } = appState.noteTags;
const hintRef = useRef<HTMLButtonElement>();
const { autocompleteSearchQuery, autocompleteTagResults } = const { autocompleteSearchQuery, autocompleteTagResults } =
appState.noteTags; appState.noteTags;
@@ -16,16 +21,46 @@ export const AutocompleteTagHint = observer(
await appState.noteTags.createAndAddNewTag(); await appState.noteTags.createAndAddNewTag();
}; };
const onFocus = () => {
appState.noteTags.setAutocompleteTagHintFocused(true);
};
const onBlur = (event: FocusEvent) => {
closeOnBlur(event);
appState.noteTags.setAutocompleteTagHintFocused(false);
};
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === 'ArrowUp') {
if (autocompleteTagResults.length > 0) {
const lastTagResult =
autocompleteTagResults[autocompleteTagResults.length - 1];
appState.noteTags.setFocusedTagResultUuid(lastTagResult.uuid);
} else {
appState.noteTags.setAutocompleteInputFocused(true);
}
}
};
useEffect(() => {
if (autocompleteTagHintFocused) {
hintRef.current.focus();
}
}, [appState.noteTags, autocompleteTagHintFocused]);
return ( return (
<> <>
{autocompleteTagResults.length > 0 && ( {autocompleteTagResults.length > 0 && (
<div className="h-1px my-2 bg-border"></div> <div className="h-1px my-2 bg-border"></div>
)} )}
<button <button
ref={hintRef}
type="button" type="button"
className="sn-dropdown-item" className="sn-dropdown-item"
onClick={onTagHintClick} onClick={onTagHintClick}
onBlur={closeOnBlur} onFocus={onFocus}
onBlur={onBlur}
onKeyDown={onKeyDown}
> >
<span>Create new tag:</span> <span>Create new tag:</span>
<span className="bg-contrast rounded text-xs color-text py-1 pl-1 pr-2 flex items-center ml-2"> <span className="bg-contrast rounded text-xs color-text py-1 pl-1 pr-2 flex items-center ml-2">

View File

@@ -61,6 +61,8 @@ export const AutocompleteTagInput = observer(({ appState }: Props) => {
event.preventDefault(); event.preventDefault();
if (autocompleteTagResults.length > 0) { if (autocompleteTagResults.length > 0) {
appState.noteTags.setFocusedTagResultUuid(autocompleteTagResults[0].uuid); appState.noteTags.setFocusedTagResultUuid(autocompleteTagResults[0].uuid);
} else if (autocompleteTagHintVisible) {
appState.noteTags.setAutocompleteTagHintFocused(true);
} }
break; break;
default: default:

View File

@@ -12,7 +12,12 @@ type Props = {
export const AutocompleteTagResult = observer( export const AutocompleteTagResult = observer(
({ appState, tagResult, closeOnBlur }: Props) => { ({ appState, tagResult, closeOnBlur }: Props) => {
const { autocompleteSearchQuery, autocompleteTagResults, focusedTagResultUuid } = appState.noteTags; const {
autocompleteSearchQuery,
autocompleteTagHintVisible,
autocompleteTagResults,
focusedTagResultUuid,
} = appState.noteTags;
const tagResultRef = useRef<HTMLButtonElement>(); const tagResultRef = useRef<HTMLButtonElement>();
@@ -23,7 +28,10 @@ export const AutocompleteTagResult = observer(
}; };
const onKeyDown = (event: KeyboardEvent) => { const onKeyDown = (event: KeyboardEvent) => {
const tagResultIndex = appState.noteTags.getTagIndex(tagResult, autocompleteTagResults); const tagResultIndex = appState.noteTags.getTagIndex(
tagResult,
autocompleteTagResults
);
switch (event.key) { switch (event.key) {
case 'ArrowUp': case 'ArrowUp':
event.preventDefault(); event.preventDefault();
@@ -35,7 +43,14 @@ export const AutocompleteTagResult = observer(
break; break;
case 'ArrowDown': case 'ArrowDown':
event.preventDefault(); event.preventDefault();
appState.noteTags.focusNextTagResult(tagResult); if (
tagResultIndex === autocompleteTagResults.length - 1 &&
autocompleteTagHintVisible
) {
appState.noteTags.setAutocompleteTagHintFocused(true);
} else {
appState.noteTags.focusNextTagResult(tagResult);
}
break; break;
default: default:
return; return;

View File

@@ -6,6 +6,7 @@ import { AppState } from './app_state';
export class NoteTagsState { export class NoteTagsState {
autocompleteInputFocused = false; autocompleteInputFocused = false;
autocompleteSearchQuery = ''; autocompleteSearchQuery = '';
autocompleteTagHintFocused = false;
autocompleteTagResults: SNTag[] = []; autocompleteTagResults: SNTag[] = [];
focusedTagResultUuid: UuidString | undefined = undefined; focusedTagResultUuid: UuidString | undefined = undefined;
focusedTagUuid: UuidString | undefined = undefined; focusedTagUuid: UuidString | undefined = undefined;
@@ -20,6 +21,7 @@ export class NoteTagsState {
makeObservable(this, { makeObservable(this, {
autocompleteInputFocused: observable, autocompleteInputFocused: observable,
autocompleteSearchQuery: observable, autocompleteSearchQuery: observable,
autocompleteTagHintFocused: observable,
autocompleteTagResults: observable, autocompleteTagResults: observable,
focusedTagUuid: observable, focusedTagUuid: observable,
focusedTagResultUuid: observable, focusedTagResultUuid: observable,
@@ -33,6 +35,7 @@ export class NoteTagsState {
focusPreviousTag: action, focusPreviousTag: action,
setAutocompleteInputFocused: action, setAutocompleteInputFocused: action,
setAutocompleteSearchQuery: action, setAutocompleteSearchQuery: action,
setAutocompleteTagHintFocused: action,
setAutocompleteTagResults: action, setAutocompleteTagResults: action,
setFocusedTagResultUuid: action, setFocusedTagResultUuid: action,
setFocusedTagUuid: action, setFocusedTagUuid: action,
@@ -69,6 +72,10 @@ export class NoteTagsState {
this.autocompleteSearchQuery = query; this.autocompleteSearchQuery = query;
} }
setAutocompleteTagHintFocused(focused: boolean): void {
this.autocompleteTagHintFocused = focused;
}
setAutocompleteTagResults(results: SNTag[]): void { setAutocompleteTagResults(results: SNTag[]): void {
this.autocompleteTagResults = results; this.autocompleteTagResults = results;
} }