refactor: refactor NoteTags for better readability
This commit is contained in:
@@ -4,7 +4,7 @@ import { toDirective } from './utils';
|
|||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import { AutocompleteTagInput } from './AutocompleteTagInput';
|
import { AutocompleteTagInput } from './AutocompleteTagInput';
|
||||||
import { WebApplication } from '@/ui_models/application';
|
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';
|
import { SNTag } from '@standardnotes/snjs';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -21,15 +21,14 @@ const NoteTags = observer(({ application, appState }: Props) => {
|
|||||||
const { tags, tagsContainerPosition, tagsContainerMaxWidth } =
|
const { tags, tagsContainerPosition, tagsContainerMaxWidth } =
|
||||||
appState.activeNote;
|
appState.activeNote;
|
||||||
|
|
||||||
const [overflowedTagsCount, setOverflowedTagsCount] = useState(0);
|
|
||||||
const [overflowCountPosition, setOverflowCountPosition] = useState(0);
|
|
||||||
const [tagsContainerCollapsed, setTagsContainerCollapsed] = useState(true);
|
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 tagsContainerRef = useRef<HTMLDivElement>();
|
||||||
const tagsRef = useRef<HTMLButtonElement[]>([]);
|
const tagsRef = useRef<HTMLButtonElement[]>([]);
|
||||||
tagsRef.current = [];
|
|
||||||
|
|
||||||
const onTagBackspacePress = async (tag: SNTag) => {
|
const onTagBackspacePress = async (tag: SNTag) => {
|
||||||
await appState.activeNote.removeTagFromActiveNote(tag);
|
await appState.activeNote.removeTagFromActiveNote(tag);
|
||||||
@@ -40,46 +39,68 @@ const NoteTags = observer(({ application, appState }: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const expandTags = () => {
|
const expandTags = () => {
|
||||||
setContainerHeight(tagsContainerRef.current.scrollHeight);
|
|
||||||
setTagsContainerCollapsed(false);
|
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(() => {
|
useEffect(() => {
|
||||||
appState.activeNote.reloadTagsContainerLayout();
|
appState.activeNote.reloadTagsContainerLayout();
|
||||||
let overflowCount = 0;
|
reloadOverflowCountPosition();
|
||||||
for (const [index, tagElement] of tagsRef.current.entries()) {
|
reloadTagsContainerHeight();
|
||||||
if (tagElement.getBoundingClientRect().top >= MIN_OVERFLOW_TOP) {
|
reloadOverflowCount();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}, [
|
}, [
|
||||||
appState.activeNote,
|
appState.activeNote,
|
||||||
|
reloadOverflowCountPosition,
|
||||||
|
reloadTagsContainerHeight,
|
||||||
|
reloadOverflowCount,
|
||||||
tags,
|
tags,
|
||||||
tagsContainerCollapsed,
|
|
||||||
tagsContainerPosition,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const tagClass = `bg-contrast border-0 rounded text-xs color-text py-1 pr-2 flex items-center
|
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`;
|
mt-2 mr-2 cursor-pointer hover:bg-secondary-contrast focus:bg-secondary-contrast`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="flex" style={{ height: tagsContainerHeight }}>
|
||||||
className="flex"
|
|
||||||
ref={containerRef}
|
|
||||||
style={{ height: containerHeight }}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
ref={tagsContainerRef}
|
ref={tagsContainerRef}
|
||||||
className={`absolute flex flex-wrap pl-1 -ml-1 ${
|
className={`absolute flex flex-wrap pl-1 -ml-1 ${
|
||||||
@@ -121,14 +142,14 @@ const NoteTags = observer(({ application, appState }: Props) => {
|
|||||||
tagsRef={tagsRef}
|
tagsRef={tagsRef}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{overflowedTagsCount > 1 && tagsContainerCollapsed && (
|
{overflowCount > 1 && tagsContainerCollapsed && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`${tagClass} pl-2 absolute`}
|
className={`${tagClass} pl-2 absolute`}
|
||||||
style={{ left: overflowCountPosition }}
|
style={{ left: overflowCountPosition }}
|
||||||
onClick={expandTags}
|
onClick={expandTags}
|
||||||
>
|
>
|
||||||
+{overflowedTagsCount}
|
+{overflowCount}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user