diff --git a/app/assets/javascripts/components/NoteTags.tsx b/app/assets/javascripts/components/NoteTags.tsx index 1eaffc0e4..3c2e2e4ba 100644 --- a/app/assets/javascripts/components/NoteTags.tsx +++ b/app/assets/javascripts/components/NoteTags.tsx @@ -4,7 +4,7 @@ import { toDirective } from './utils'; import { Icon } from './Icon'; import { AutocompleteTagInput } from './AutocompleteTagInput'; import { WebApplication } from '@/ui_models/application'; -import { useEffect, useRef, useState } from 'preact/hooks'; +import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; import { SNTag } from '@standardnotes/snjs'; type Props = { @@ -21,15 +21,14 @@ const NoteTags = observer(({ application, appState }: Props) => { const { tags, tagsContainerPosition, tagsContainerMaxWidth } = appState.activeNote; - const [overflowedTagsCount, setOverflowedTagsCount] = useState(0); - const [overflowCountPosition, setOverflowCountPosition] = useState(0); const [tagsContainerCollapsed, setTagsContainerCollapsed] = useState(true); - const [containerHeight, setContainerHeight] = useState(TAGS_ROW_HEIGHT); + const [tagsContainerHeight, setTagsContainerHeight] = + useState(TAGS_ROW_HEIGHT); + const [overflowCountPosition, setOverflowCountPosition] = useState(0); + const [overflowCount, setOverflowCount] = useState(0); - const containerRef = useRef(); const tagsContainerRef = useRef(); const tagsRef = useRef([]); - tagsRef.current = []; const onTagBackspacePress = async (tag: SNTag) => { await appState.activeNote.removeTagFromActiveNote(tag); @@ -40,46 +39,68 @@ const NoteTags = observer(({ application, appState }: Props) => { }; const expandTags = () => { - setContainerHeight(tagsContainerRef.current.scrollHeight); setTagsContainerCollapsed(false); }; + const isTagOverflowed = useCallback( + (tagElement?: HTMLButtonElement): boolean | undefined => { + if (!tagElement) { + return; + } + if (!tagsContainerCollapsed) { + return false; + } + return tagElement.getBoundingClientRect().top >= MIN_OVERFLOW_TOP; + }, + [tagsContainerCollapsed] + ); + + const reloadOverflowCountPosition = useCallback(() => { + const firstOverflowedTagIndex = tagsRef.current.findIndex((tagElement) => + isTagOverflowed(tagElement) + ); + if (!tagsContainerCollapsed || firstOverflowedTagIndex < 1) { + return; + } + const previousTagRect = + tagsRef.current[firstOverflowedTagIndex - 1].getBoundingClientRect(); + const position = + previousTagRect.right - (tagsContainerPosition ?? 0) + TAGS_RIGHT_MARGIN; + setOverflowCountPosition(position); + }, [isTagOverflowed, tagsContainerCollapsed, tagsContainerPosition]); + + const reloadTagsContainerHeight = useCallback(() => { + const height = tagsContainerCollapsed + ? TAGS_ROW_HEIGHT + : tagsContainerRef.current.scrollHeight; + setTagsContainerHeight(height); + }, [tagsContainerCollapsed]); + + const reloadOverflowCount = useCallback(() => { + const count = tagsRef.current.filter((tagElement) => + isTagOverflowed(tagElement) + ).length; + setOverflowCount(count); + }, [isTagOverflowed]); + useEffect(() => { appState.activeNote.reloadTagsContainerLayout(); - let overflowCount = 0; - for (const [index, tagElement] of tagsRef.current.entries()) { - if (tagElement.getBoundingClientRect().top >= MIN_OVERFLOW_TOP) { - if (overflowCount === 0) { - setOverflowCountPosition( - tagsRef.current[index - 1].getBoundingClientRect().right - - (tagsContainerPosition ?? 0) + - TAGS_RIGHT_MARGIN - ); - } - overflowCount += 1; - } - } - setOverflowedTagsCount(overflowCount); - - if (!tagsContainerCollapsed) { - setContainerHeight(tagsContainerRef.current.scrollHeight); - } + reloadOverflowCountPosition(); + reloadTagsContainerHeight(); + reloadOverflowCount(); }, [ appState.activeNote, + reloadOverflowCountPosition, + reloadTagsContainerHeight, + reloadOverflowCount, tags, - tagsContainerCollapsed, - tagsContainerPosition, ]); const tagClass = `bg-contrast border-0 rounded text-xs color-text py-1 pr-2 flex items-center mt-2 mr-2 cursor-pointer hover:bg-secondary-contrast focus:bg-secondary-contrast`; return ( -
+
{ tagsRef={tagsRef} />
- {overflowedTagsCount > 1 && tagsContainerCollapsed && ( + {overflowCount > 1 && tagsContainerCollapsed && ( )}