Skip to content

Commit

Permalink
fix: make sure input is visible when no tags are overflowed
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonella Sgarlatta committed Jun 2, 2021
1 parent 53a55d4 commit 3db8709
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 35 deletions.
29 changes: 23 additions & 6 deletions app/assets/javascripts/components/AutocompleteTagInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { WebApplication } from '@/ui_models/application';
import { SNTag } from '@standardnotes/snjs';
import { FunctionalComponent, RefObject } from 'preact';
import { useEffect, useRef, useState } from 'preact/hooks';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { Icon } from './Icon';
import { Disclosure, DisclosurePanel } from '@reach/disclosure';
import { useCloseOnBlur } from './utils';
Expand All @@ -11,15 +11,15 @@ type Props = {
application: WebApplication;
appState: AppState;
tagsRef: RefObject<HTMLButtonElement[]>;
tabIndex: number;
};

export const AutocompleteTagInput: FunctionalComponent<Props> = ({
application,
appState,
tagsRef,
tabIndex,
}) => {
const { tags, tagsContainerMaxWidth, tagsOverflowed } = appState.activeNote;

const [searchQuery, setSearchQuery] = useState('');
const [dropdownVisible, setDropdownVisible] = useState(false);
const [dropdownMaxHeight, setDropdownMaxHeight] =
Expand Down Expand Up @@ -84,6 +84,23 @@ export const AutocompleteTagInput: FunctionalComponent<Props> = ({
await createAndAddNewTag();
};

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;
}
appState.activeNote.setInputOverflowed(overflowed);
}, [appState.activeNote, tagsOverflowed, tagsRef]);

useEffect(() => {
reloadInputOverflowed();
}, [
reloadInputOverflowed,
tagsContainerMaxWidth,
tags,
]);

useEffect(() => {
setHintVisible(
searchQuery !== '' && !tagResults.some((tag) => tag.title === searchQuery)
Expand All @@ -100,7 +117,7 @@ export const AutocompleteTagInput: FunctionalComponent<Props> = ({
onChange={onSearchQueryChange}
type="text"
placeholder="Add tag"
tabIndex={tabIndex}
tabIndex={tagsOverflowed ? -1 : 0}
onBlur={closeOnBlur}
onFocus={showDropdown}
onKeyUp={(event) => {
Expand Down Expand Up @@ -129,7 +146,7 @@ export const AutocompleteTagInput: FunctionalComponent<Props> = ({
className="sn-dropdown-item"
onClick={() => onTagOptionClick(tag)}
onBlur={closeOnBlur}
tabIndex={tabIndex}
tabIndex={tagsOverflowed ? -1 : 0}
>
<Icon type="hashtag" className="color-neutral mr-2 min-h-5 min-w-5" />
<span className="whitespace-nowrap overflow-hidden overflow-ellipsis">
Expand Down Expand Up @@ -167,7 +184,7 @@ export const AutocompleteTagInput: FunctionalComponent<Props> = ({
className="sn-dropdown-item"
onClick={onTagHintClick}
onBlur={closeOnBlur}
tabIndex={tabIndex}
tabIndex={tagsOverflowed ? -1 : 0}
>
<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">
Expand Down
36 changes: 20 additions & 16 deletions app/assets/javascripts/components/NoteTagsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ type Props = {

const NoteTagsContainer = observer(({ application, appState }: Props) => {
const {
inputOverflowed,
overflowedTagsCount,
tags,
tagsContainerMaxWidth,
tagsContainerExpanded,
tagsOverflowed,
} = appState.activeNote;

const [expandedContainerHeight, setExpandedContainerHeight] = useState(0);
const [lastVisibleTagIndex, setLastVisibleTagIndex] =
useState<number | null>(null);
Expand Down Expand Up @@ -82,8 +83,10 @@ const NoteTagsContainer = observer(({ application, appState }: Props) => {
return;
}
if (tagsRef.current[lastVisibleTagIndex]) {
const { offsetLeft: lastVisibleTagLeft, clientWidth: lastVisibleTagWidth } =
tagsRef.current[lastVisibleTagIndex];
const {
offsetLeft: lastVisibleTagLeft,
clientWidth: lastVisibleTagWidth,
} = tagsRef.current[lastVisibleTagIndex];
setOverflowCountPosition(lastVisibleTagLeft + lastVisibleTagWidth);
}
}, [lastVisibleTagIndex, tagsContainerExpanded]);
Expand All @@ -108,19 +111,17 @@ const NoteTagsContainer = observer(({ application, appState }: Props) => {

useEffect(() => {
reloadTagsContainerLayout();
}, [
reloadTagsContainerLayout,
tags,
tagsContainerMaxWidth,
]);
}, [reloadTagsContainerLayout, tags, tagsContainerMaxWidth]);

useEffect(() => {
let tagResizeObserver: ResizeObserver;
if (ResizeObserver) {
tagResizeObserver = new ResizeObserver(() => {
reloadTagsContainerLayout();
});
tagsRef.current.forEach((tagElement) => tagResizeObserver.observe(tagElement));
tagsRef.current.forEach((tagElement) =>
tagResizeObserver.observe(tagElement)
);
}

return () => {
Expand All @@ -132,15 +133,17 @@ const NoteTagsContainer = observer(({ application, appState }: Props) => {

return (
<div
className="flex transition-height duration-150 h-9 relative"
className={`flex transition-height duration-150 relative ${
inputOverflowed ? 'h-18' : 'h-9'
}`}
ref={containerRef}
style={tagsContainerExpanded ? { height: expandedContainerHeight } : {}}
>
<div
ref={tagsContainerRef}
className={`absolute bg-default h-9 flex flex-wrap pl-1 -ml-1 ${
tagsContainerExpanded ? '' : 'overflow-hidden'
}`}
className={`absolute bg-default flex flex-wrap pl-1 -ml-1 ${
inputOverflowed ? 'h-18' : 'h-9'
} ${tagsContainerExpanded || !tagsOverflowed ? '' : 'overflow-hidden'}`}
style={{
maxWidth: tagsContainerMaxWidth,
}}
Expand All @@ -152,16 +155,17 @@ const NoteTagsContainer = observer(({ application, appState }: Props) => {
index={index}
tag={tag}
maxWidth={tagsContainerMaxWidth}
overflowed={!tagsContainerExpanded &&
overflowed={
!tagsContainerExpanded &&
!!lastVisibleTagIndex &&
index > lastVisibleTagIndex}
index > lastVisibleTagIndex
}
/>
))}
<AutocompleteTagInput
application={application}
appState={appState}
tagsRef={tagsRef}
tabIndex={tagsOverflowed ? -1 : 0}
/>
</div>
{tagsOverflowed && (
Expand Down
33 changes: 20 additions & 13 deletions app/assets/javascripts/ui_models/app_state/active_note_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,33 @@ import { WebApplication } from '../application';
import { AppState } from './app_state';

export class ActiveNoteState {
inputOverflowed = false;
overflowedTagsCount = 0;
tags: SNTag[] = [];
tagsContainerMaxWidth: number | 'auto' = 0;
tagsContainerExpanded = false;
overflowedTagsCount = 0;
tagFocused = false;
tagsContainerExpanded = false;

constructor(
private application: WebApplication,
private appState: AppState,
appEventListeners: (() => void)[]
) {
makeObservable(this, {
tags: observable,
tagsContainerMaxWidth: observable,
tagsContainerExpanded: observable,
inputOverflowed: observable,
overflowedTagsCount: observable,
tags: observable,
tagFocused: observable,
tagsContainerExpanded: observable,
tagsContainerMaxWidth: observable,

tagsOverflowed: computed,

setTagsContainerMaxWidth: action,
setTagsContainerExpanded: action,
setInputOverflowed: action,
setOverflowedTagsCount: action,
setTagFocused: action,
setTagsContainerExpanded: action,
setTagsContainerMaxWidth: action,
reloadTags: action,
});

Expand All @@ -58,12 +61,8 @@ export class ActiveNoteState {
return this.overflowedTagsCount > 0 && !this.tagsContainerExpanded;
}

setTagsContainerMaxWidth(width: number): void {
this.tagsContainerMaxWidth = width;
}

setTagsContainerExpanded(expanded: boolean): void {
this.tagsContainerExpanded = expanded;
setInputOverflowed(overflowed: boolean): void {
this.inputOverflowed = overflowed;
}

setOverflowedTagsCount(count: number): void {
Expand All @@ -74,6 +73,14 @@ export class ActiveNoteState {
this.tagFocused = focused;
}

setTagsContainerExpanded(expanded: boolean): void {
this.tagsContainerExpanded = expanded;
}

setTagsContainerMaxWidth(width: number): void {
this.tagsContainerMaxWidth = width;
}

reloadTags(): void {
const { activeNote } = this;
if (activeNote) {
Expand Down
4 changes: 4 additions & 0 deletions app/assets/stylesheets/_sn.scss
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@
height: 2.5rem;
}

.h-18 {
height: 4.5rem;
}

.max-h-120 {
max-height: 30rem;
}
Expand Down

0 comments on commit 3db8709

Please sign in to comment.