mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-26 17:34:41 +00:00
Fix: Add support of auto positioning for tag's drop-down (#1169)
* Feat: add auto position feature for tag dropdown * increase buffer space by 50px
This commit is contained in:
parent
055f629cab
commit
04f1903481
@ -16,9 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isNil, lowerCase } from 'lodash';
|
import { isNil, isUndefined, lowerCase } from 'lodash';
|
||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
||||||
|
import { useWindowDimensions } from '../../hooks/useWindowDimensions';
|
||||||
import { getCountBadge } from '../../utils/CommonUtils';
|
import { getCountBadge } from '../../utils/CommonUtils';
|
||||||
|
import { getTopPosition } from '../../utils/DropDownUtils';
|
||||||
import { DropDownListItem, DropDownListProp } from './types';
|
import { DropDownListItem, DropDownListProp } from './types';
|
||||||
|
|
||||||
const DropDownList: FunctionComponent<DropDownListProp> = ({
|
const DropDownList: FunctionComponent<DropDownListProp> = ({
|
||||||
@ -30,10 +32,15 @@ const DropDownList: FunctionComponent<DropDownListProp> = ({
|
|||||||
value,
|
value,
|
||||||
onSelect,
|
onSelect,
|
||||||
groupType = 'label',
|
groupType = 'label',
|
||||||
|
domPosition,
|
||||||
}: DropDownListProp) => {
|
}: DropDownListProp) => {
|
||||||
|
const { height: windowHeight } = useWindowDimensions();
|
||||||
const isMounted = useRef<boolean>(false);
|
const isMounted = useRef<boolean>(false);
|
||||||
const [searchedList, setSearchedList] = useState(dropDownList);
|
const [searchedList, setSearchedList] = useState(dropDownList);
|
||||||
const [searchText, setSearchText] = useState(searchString);
|
const [searchText, setSearchText] = useState(searchString);
|
||||||
|
const [dropDownPosition, setDropDownPosition] = useState<
|
||||||
|
{ bottom: string } | {}
|
||||||
|
>({});
|
||||||
|
|
||||||
const setCurrentTabOnMount = () => {
|
const setCurrentTabOnMount = () => {
|
||||||
const selectedItem = dropDownList.find((l) => l.value === value);
|
const selectedItem = dropDownList.find((l) => l.value === value);
|
||||||
@ -109,6 +116,14 @@ const DropDownList: FunctionComponent<DropDownListProp> = ({
|
|||||||
}
|
}
|
||||||
}, [searchText]);
|
}, [searchText]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isUndefined(domPosition)) {
|
||||||
|
setDropDownPosition(
|
||||||
|
getTopPosition(windowHeight, domPosition.bottom, domPosition.height)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [domPosition, searchText]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setActiveTab(setCurrentTabOnMount());
|
setActiveTab(setCurrentTabOnMount());
|
||||||
isMounted.current = true;
|
isMounted.current = true;
|
||||||
@ -134,7 +149,8 @@ const DropDownList: FunctionComponent<DropDownListProp> = ({
|
|||||||
horzPosRight ? 'dd-horz-right' : 'dd-horz-left'
|
horzPosRight ? 'dd-horz-right' : 'dd-horz-left'
|
||||||
)}
|
)}
|
||||||
data-testid="dropdown-list"
|
data-testid="dropdown-list"
|
||||||
role="menu">
|
role="menu"
|
||||||
|
style={dropDownPosition}>
|
||||||
{showSearchBar && (
|
{showSearchBar && (
|
||||||
<div className="has-search tw-p-4 tw-pb-2">
|
<div className="has-search tw-p-4 tw-pb-2">
|
||||||
<input
|
<input
|
||||||
|
@ -53,6 +53,7 @@ export type DropDownListProp = {
|
|||||||
) => void;
|
) => void;
|
||||||
setIsOpen?: (value: boolean) => void;
|
setIsOpen?: (value: boolean) => void;
|
||||||
groupType?: GroupType;
|
groupType?: GroupType;
|
||||||
|
domPosition?: DOMRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DropDownProp = {
|
export type DropDownProp = {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { capitalize, isEmpty } from 'lodash';
|
import { capitalize, isEmpty, isNull } from 'lodash';
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
||||||
import { Button } from '../buttons/Button/Button';
|
import { Button } from '../buttons/Button/Button';
|
||||||
@ -43,6 +43,7 @@ const TagsContainer: FunctionComponent<TagsContainerProps> = ({
|
|||||||
const [hasFocus, setFocus] = useState<boolean>(false);
|
const [hasFocus, setFocus] = useState<boolean>(false);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const node = useRef<HTMLDivElement>(null);
|
const node = useRef<HTMLDivElement>(null);
|
||||||
|
const [inputDomRect, setInputDomRect] = useState<DOMRect>();
|
||||||
// const [inputWidth, setInputWidth] = useState(INPUT_COLLAPED);
|
// const [inputWidth, setInputWidth] = useState(INPUT_COLLAPED);
|
||||||
// const [inputMinWidth, setInputMinWidth] = useState(INPUT_AUTO);
|
// const [inputMinWidth, setInputMinWidth] = useState(INPUT_AUTO);
|
||||||
|
|
||||||
@ -64,6 +65,12 @@ const TagsContainer: FunctionComponent<TagsContainerProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isNull(inputRef.current)) {
|
||||||
|
setInputDomRect(inputRef.current.getBoundingClientRect());
|
||||||
|
}
|
||||||
|
}, [newTag]);
|
||||||
|
|
||||||
const getTagList = () => {
|
const getTagList = () => {
|
||||||
const newTags = tagList
|
const newTags = tagList
|
||||||
.filter((tag) => {
|
.filter((tag) => {
|
||||||
@ -227,6 +234,7 @@ const TagsContainer: FunctionComponent<TagsContainerProps> = ({
|
|||||||
{newTag && (
|
{newTag && (
|
||||||
<DropDownList
|
<DropDownList
|
||||||
horzPosRight
|
horzPosRight
|
||||||
|
domPosition={inputDomRect}
|
||||||
dropDownList={getTagList()}
|
dropDownList={getTagList()}
|
||||||
searchString={newTag}
|
searchString={newTag}
|
||||||
onSelect={handleTagSelection}
|
onSelect={handleTagSelection}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
function getWindowDimensions() {
|
||||||
|
const { innerWidth: width, innerHeight: height } = window;
|
||||||
|
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWindowDimensions() {
|
||||||
|
const [windowDimensions, setWindowDimensions] = useState(
|
||||||
|
getWindowDimensions()
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleResize() {
|
||||||
|
setWindowDimensions(getWindowDimensions());
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return windowDimensions;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
const BUFFER_VALUE = 200;
|
||||||
|
const GAP = 10;
|
||||||
|
|
||||||
|
export const getTopPosition = (
|
||||||
|
windowHeight: number,
|
||||||
|
bottomPosition: number,
|
||||||
|
elementHeight: number
|
||||||
|
) => {
|
||||||
|
const bottomSpace = windowHeight - (bottomPosition + BUFFER_VALUE);
|
||||||
|
|
||||||
|
return bottomSpace < 0 ? { bottom: `${elementHeight + GAP}px` } : {};
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user