Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix/BAR-235] Dropdown 컴포넌트 위치 오류 해결 #65

Merged
merged 4 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .storybook/preview-body.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
<div id="modal-root" />
<div id="toast-root" />
<div id="tooltip-root" />
<div id="dropdown-root" />
28 changes: 11 additions & 17 deletions src/components/Dropdown/components/DropdownList.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import { type PropsWithChildren } from 'react';
import { assignInlineVars } from '@vanilla-extract/dynamic';

import Portal from '@components/Portal';
import { PORTAL_ID } from '@constants/portal';

import { useDropdownContext } from '..';
import * as styles from '../style.css';

const DropdownList = ({ children }: PropsWithChildren) => {
const { size, targetRef, position, fixed, isOpen } = useDropdownContext();
const { isOpen, targetRef, size, position } = useDropdownContext();

return (
<>
{isOpen && (
<Portal id={PORTAL_ID['DROPDOWN']}>
<ul
ref={targetRef}
className={styles.menuList({ size })}
style={assignInlineVars({
[styles.position]: fixed ? 'fixed' : 'absolute',
[styles.top]: `${position.top}px`,
[styles.left]: `${position.left}px`,
})}
>
{children}
</ul>
</Portal>
<ul
ref={targetRef}
className={styles.menuList({ size })}
style={assignInlineVars({
[styles.top]: `${position.top}px`,
[styles.left]: `${position.left}px`,
})}
>
{children}
</ul>
)}
</>
);
Expand Down
9 changes: 2 additions & 7 deletions src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ interface DropdownContextProps {
position: typeof INIT_POSITION;
/** dropdown menulist 요소의 ref 객체 */
targetRef: RefObject<HTMLUListElement>;
/** dropdown menulist css position fixed 적용 여부 */
fixed?: boolean;
/** dropdown menulist 열림, 닫힘 상태 */
isOpen: boolean;
/** dropdown trigger toggle 함수 */
Expand All @@ -38,7 +36,7 @@ interface DropdownContextProps {

interface DropdownRootProps
extends HTMLAttributes<HTMLDivElement>,
Pick<DropdownContextProps, 'size' | 'placement' | 'fixed'> {
Pick<DropdownContextProps, 'size' | 'placement'> {
className?: HTMLAttributes<HTMLDivElement>['className'];
}

Expand All @@ -48,19 +46,17 @@ const DropdownRoot = ({
children,
size = 'small',
placement = 'bottom-left',
fixed = false,
...props
}: PropsWithChildren<DropdownRootProps>) => {
const { isOpen, onClose, onToggle } = useDisclosure();
const dropdownRef = useClickAway({
onClickAway: onClose,
});
})!;
const { targetRef, position } = usePosition<HTMLDivElement, HTMLUListElement>(
{
defaultTriggerRef: dropdownRef,
isOpen,
placement,
fixed,
},
);

Expand All @@ -71,7 +67,6 @@ const DropdownRoot = ({
placement,
position,
targetRef,
fixed,
isOpen,
onToggle,
}}
Expand Down
3 changes: 1 addition & 2 deletions src/components/Dropdown/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ export const trigger = style({
width: 'fit-content',
});

export const position = createVar();
export const top = createVar();
export const left = createVar();

export const menuList = recipe({
base: {
position,
position: 'absolute',
top,
left,
marginTop: '4px',
Expand Down
1 change: 0 additions & 1 deletion src/components/Layout/components/ProfileButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const ProfileButton = () => {
className={styles.dialogWrapper}
size="medium"
placement="bottom-right"
fixed
>
<Dropdown.Trigger className={styles.profile}>
<Icon icon="profileHeader" width={28} height={28} />
Expand Down
35 changes: 15 additions & 20 deletions src/components/Tooltip/components/TooltipContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import type { PropsWithChildren } from 'react';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';

import { PORTAL_ID } from '@constants/portal';

import Portal from '../../Portal';
import { useTooltipContext } from '..';
import * as styles from '../style.css';

Expand All @@ -28,23 +25,21 @@ const TooltipContent = ({ children }: PropsWithChildren) => {
return (
<>
{isOpen && (
<Portal id={PORTAL_ID['TOOLTIP']}>
<div
ref={targetRef}
className={clsx(
styles.content({ hasArrow }),
hasArrow && placement && ARROW_STYLE[placement],
isTopMinimalTooltip && MARGIN_STYLE.MINIMAL,
isTopHighlightTooltip && MARGIN_STYLE.HIGHLIGHT,
)}
style={assignInlineVars({
[styles.top]: `${position.top}px`,
[styles.left]: `${position.left}px`,
})}
>
{children}
</div>
</Portal>
<div
ref={targetRef}
className={clsx(
styles.content({ hasArrow }),
hasArrow && placement && ARROW_STYLE[placement],
isTopMinimalTooltip && MARGIN_STYLE.MINIMAL,
isTopHighlightTooltip && MARGIN_STYLE.HIGHLIGHT,
)}
style={assignInlineVars({
[styles.top]: `${position.top}px`,
[styles.left]: `${position.left}px`,
})}
>
{children}
</div>
)}
</>
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/Tooltip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import usePosition from '@hooks/usePosition';

import TooltipContent from './components/TooltipContent';
import TooltipTrigger from './components/TooltipTrigger';
import * as styles from './style.css';

const INIT_POSITION = { top: 0, left: 0 };

Expand Down Expand Up @@ -51,7 +52,9 @@ const TooltipRoot = ({
onClose,
}}
>
<div ref={triggerRef}>{children}</div>
<div ref={triggerRef} className={styles.wrapper}>
{children}
</div>
</TooltipContext.Provider>
);
};
Expand Down
4 changes: 4 additions & 0 deletions src/components/Tooltip/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { recipe } from '@vanilla-extract/recipes';
import { sprinkles } from '@styles/sprinkles.css';
import { COLORS, Z_INDEX } from '@styles/tokens';

export const wrapper = style({
position: 'relative',
});

export const trigger = style({
width: 'fit-content',
height: 'fit-content',
Expand Down
2 changes: 0 additions & 2 deletions src/constants/portal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export const PORTAL_ID = {
MODAL: 'modal-root',
TOAST: 'toast-root',
TOOLTIP: 'tooltip-root',
DROPDOWN: 'dropdown-root',
} as const;
22 changes: 8 additions & 14 deletions src/hooks/usePosition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,24 @@ const usePosition = <
const ref = useRef<T>(null);
const triggerRef = defaultTriggerRef || ref;
const targetRef = useRef<U>(null);

const [position, setPosition] = useState(POSITION);

useEffect(() => {
if (!triggerRef.current || !targetRef.current || !isOpen) {
return;
}

const {
x,
y,
bottom: triggerBottom,
width: triggerWidth,
height: triggerHeight,
} = triggerRef.current.getBoundingClientRect();
const { width: triggerWidth, height: triggerHeight } =
triggerRef.current.getBoundingClientRect();
const { width: targetWidth } = targetRef.current.getBoundingClientRect();

const { scrollX, scrollY } = window;

const top = y + scrollY - triggerHeight;
const bottom = !fixed ? y + scrollY + triggerHeight : triggerBottom;
const top = -triggerHeight;
const bottom = triggerHeight;

const left = x + scrollX;
const center = left + triggerWidth / 2 - targetWidth / 2;
const right = left + triggerWidth - targetWidth;
const left = 0;
const center = triggerWidth / 2 - targetWidth / 2;
const right = triggerWidth - targetWidth;

const CALCULATED_POSITION: Record<Placement, typeof POSITION> = {
'top-left': { top, left },
Expand Down
Loading