diff --git a/app/assets/javascripts/components/AutocompleteTagInput.tsx b/app/assets/javascripts/components/AutocompleteTagInput.tsx index 09cdfaa82..7a33af117 100644 --- a/app/assets/javascripts/components/AutocompleteTagInput.tsx +++ b/app/assets/javascripts/components/AutocompleteTagInput.tsx @@ -1,6 +1,6 @@ import { WebApplication } from '@/ui_models/application'; import { SNTag } from '@standardnotes/snjs'; -import { FunctionalComponent, RefObject } from 'preact'; +import { FunctionalComponent } from 'preact'; import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; import { Icon } from './Icon'; import { Disclosure, DisclosurePanel } from '@reach/disclosure'; @@ -10,15 +10,13 @@ import { AppState } from '@/ui_models/app_state'; type Props = { application: WebApplication; appState: AppState; - tagsRef: RefObject; }; export const AutocompleteTagInput: FunctionalComponent = ({ application, appState, - tagsRef, }) => { - const { tags, tagsContainerMaxWidth, tagsOverflowed } = appState.activeNote; + const { tagElements, tags, tagsContainerMaxWidth, tagsOverflowed } = appState.activeNote; const [searchQuery, setSearchQuery] = useState(''); const [dropdownVisible, setDropdownVisible] = useState(false); @@ -85,13 +83,9 @@ export const AutocompleteTagInput: FunctionalComponent = ({ }; const reloadInputOverflowed = useCallback(() => { - let overflowed = false; - if (!tagsOverflowed && tagsRef.current && tagsRef.current.length > 0) { - const firstTagTop = tagsRef.current[0].offsetTop; - overflowed = inputRef.current.offsetTop > firstTagTop; - } + const overflowed = !tagsOverflowed && appState.activeNote.isElementOverflowed(inputRef.current); appState.activeNote.setInputOverflowed(overflowed); - }, [appState.activeNote, tagsOverflowed, tagsRef]); + }, [appState.activeNote, tagsOverflowed]); useEffect(() => { reloadInputOverflowed(); @@ -124,10 +118,9 @@ export const AutocompleteTagInput: FunctionalComponent = ({ if ( event.key === 'Backspace' && searchQuery === '' && - tagsRef.current && - tagsRef.current.length > 1 + tagElements.length > 0 ) { - tagsRef.current[tagsRef.current.length - 1].focus(); + tagElements[tagElements.length - 1]?.focus(); } }} /> diff --git a/app/assets/javascripts/components/NoteTag.tsx b/app/assets/javascripts/components/NoteTag.tsx index f3f5a0d8d..dae7b727f 100644 --- a/app/assets/javascripts/components/NoteTag.tsx +++ b/app/assets/javascripts/components/NoteTag.tsx @@ -1,34 +1,34 @@ import { Icon } from './Icon'; import { FunctionalComponent, RefObject } from 'preact'; -import { useRef, useState } from 'preact/hooks'; +import { useCallback, useRef, useState } from 'preact/hooks'; import { AppState } from '@/ui_models/app_state'; import { SNTag } from '@standardnotes/snjs/dist/@types'; +import { useEffect } from 'react'; type Props = { appState: AppState; - index: number; - tagsRef: RefObject; tag: SNTag; - overflowed: boolean; - maxWidth: number | 'auto'; + overflowButtonRef: RefObject; }; -export const NoteTag: FunctionalComponent = ({ - appState, - index, - tagsRef, - tag, - overflowed, - maxWidth, -}) => { +export const NoteTag: FunctionalComponent = ({ appState, tag, overflowButtonRef }) => { + const { + tags, + tagsContainerMaxWidth, + } = appState.activeNote; + + const [overflowed, setOverflowed] = useState(false); const [showDeleteButton, setShowDeleteButton] = useState(false); + const deleteTagRef = useRef(); const deleteTag = async () => { await appState.activeNote.removeTagFromActiveNote(tag); + const previousTag = appState.activeNote.getPreviousTag(tag); - if (index > 0 && tagsRef.current) { - tagsRef.current[index - 1].focus(); + if (previousTag) { + const previousTagElement = appState.activeNote.getTagElement(previousTag); + previousTagElement?.focus(); } }; @@ -42,21 +42,33 @@ export const NoteTag: FunctionalComponent = ({ }; const onBlur = (event: FocusEvent) => { - appState.activeNote.setTagFocused(false); - if ((event.relatedTarget as Node) !== deleteTagRef.current) { + const relatedTarget = event.relatedTarget as Node; + if (relatedTarget === overflowButtonRef.current) { + (event.target as HTMLButtonElement).focus(); + } else if (relatedTarget !== deleteTagRef.current) { + appState.activeNote.setTagFocused(false); setShowDeleteButton(false); } }; + const reloadOverflowed = useCallback(() => { + const overflowed = appState.activeNote.isTagOverflowed(tag); + setOverflowed(overflowed); + }, [appState.activeNote, tag]); + + useEffect(() => { + reloadOverflowed(); + }, [reloadOverflowed, tags, tagsContainerMaxWidth]); + return (