refactor: refactor NoteTags for better readability
This commit is contained in:
@@ -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<HTMLDivElement>();
|
||||
const tagsContainerRef = useRef<HTMLDivElement>();
|
||||
const tagsRef = useRef<HTMLButtonElement[]>([]);
|
||||
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 (
|
||||
<div
|
||||
className="flex"
|
||||
ref={containerRef}
|
||||
style={{ height: containerHeight }}
|
||||
>
|
||||
<div className="flex" style={{ height: tagsContainerHeight }}>
|
||||
<div
|
||||
ref={tagsContainerRef}
|
||||
className={`absolute flex flex-wrap pl-1 -ml-1 ${
|
||||
@@ -121,14 +142,14 @@ const NoteTags = observer(({ application, appState }: Props) => {
|
||||
tagsRef={tagsRef}
|
||||
/>
|
||||
</div>
|
||||
{overflowedTagsCount > 1 && tagsContainerCollapsed && (
|
||||
{overflowCount > 1 && tagsContainerCollapsed && (
|
||||
<button
|
||||
type="button"
|
||||
className={`${tagClass} pl-2 absolute`}
|
||||
style={{ left: overflowCountPosition }}
|
||||
onClick={expandTags}
|
||||
>
|
||||
+{overflowedTagsCount}
|
||||
+{overflowCount}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user