UNPKG

@modern-kit/react

Version:
1 lines 9.61 kB
{"version":3,"file":"index.mjs","sources":["../../../src/hooks/useScrollTo/useScrollTo.utils.ts","../../../src/hooks/useScrollTo/index.ts"],"sourcesContent":["import { isWindow } from '@modern-kit/utils';\n\nexport interface ScrollToElementOptions {\n offsetX?: number;\n offsetY?: number;\n behavior?: ScrollBehavior;\n alignY?: Align; // 수직\n alignX?: Align; // 수평\n}\n\ntype Align = 'start' | 'center' | 'end';\n\ninterface Position {\n top: number;\n left: number;\n}\n\ntype CalculatePositionOptions = Required<\n Pick<ScrollToElementOptions, 'offsetX' | 'offsetY' | 'alignX' | 'alignY'>\n>;\n\n/**\n * @description 컨테이너 내에서 타겟 요소의 정렬 위치를 계산합니다.\n */\nconst getAlignPosition = (\n containerDimension: number,\n targetDimension: number,\n align: Align\n) => {\n if (align === 'start') {\n return 0;\n }\n if (align === 'center') {\n return -containerDimension / 2 + targetDimension / 2;\n }\n return -containerDimension + targetDimension;\n};\n\n/**\n * @description 윈도우를 기준으로 타겟 요소의 위치를 계산합니다.\n */\nconst calculateTargetPositionFromWindow = (\n targetRect: DOMRect,\n options: CalculatePositionOptions\n): Position => ({\n top:\n targetRect.top +\n window.scrollY +\n options.offsetY +\n getAlignPosition(window.innerHeight, targetRect.height, options.alignY),\n left:\n targetRect.left +\n window.scrollX +\n options.offsetX +\n getAlignPosition(window.innerWidth, targetRect.width, options.alignX),\n});\n\n/**\n * @description 특정 컨테이너 요소를 기준으로 타겟 요소의 스크롤 위치를 계산합니다.\n */\nconst calculateTargetPositionFromElement = (\n targetRect: DOMRect,\n container: HTMLElement,\n options: CalculatePositionOptions\n): Position => {\n const containerRect = container.getBoundingClientRect();\n\n return {\n top:\n targetRect.top -\n containerRect.top +\n container.scrollTop +\n options.offsetY +\n getAlignPosition(containerRect.height, targetRect.height, options.alignY),\n left:\n targetRect.left -\n containerRect.left +\n container.scrollLeft +\n options.offsetX +\n getAlignPosition(containerRect.width, targetRect.width, options.alignX),\n };\n};\n\n/**\n * @description parent가 window인지 특정 요소인지에 child의 위치 값을 가져오는 함수\n */\nexport const getRelativePosition = <T extends HTMLElement>(\n container: T | Window,\n target: HTMLElement,\n scrollToOptions: ScrollToElementOptions\n): Position => {\n const targetRect = target.getBoundingClientRect();\n const options = {\n offsetX: scrollToOptions?.offsetX ?? 0,\n offsetY: scrollToOptions?.offsetY ?? 0,\n alignY: scrollToOptions?.alignY ?? 'start',\n alignX: scrollToOptions?.alignX ?? 'start',\n };\n\n return isWindow(container)\n ? calculateTargetPositionFromWindow(targetRect, options)\n : calculateTargetPositionFromElement(targetRect, container, options);\n};\n","import React, { useCallback, useRef } from 'react';\nimport {\n ScrollToElementOptions,\n getRelativePosition,\n} from './useScrollTo.utils';\n\ninterface UseScrollToReturnType<T extends HTMLElement> {\n containerRef: React.RefObject<T>;\n scrollToPosition: (scrollToOptions?: ScrollToOptions) => void;\n scrollToElement: <E extends HTMLElement>(\n target: E,\n scrollToElementOptions?: ScrollToElementOptions\n ) => void;\n}\n\n/**\n * @description 스크롤 기능을 제공하는 커스텀 훅입니다.\n *\n * 훅이 반환하는 `containerRef`를 특정 엘리먼트에 할당하면 해당 컨테이너 요소를 스크롤 합니다.\n * 만약, `containerRef`를 할당하지 않으면 기본적으로 `window`를 스크롤합니다.\n *\n * @template T - 스크롤이 이루어질 컨테이너 요소의 타입입니다.\n * @returns {UseScrollToReturnType<T>} 스크롤 요소를 지정 할 `containerRef`와 스크롤을 동작 시킬 `scrollToPosition`, `scrollToElement` 함수를 포함하는 객체입니다.\n * - `containerRef`: 스크롤을 제어할 컨테이너 요소에 대한 ref입니다. 설정하지 않으면 `window`가 기본값으로 설정됩니다.\n * - `scrollToPosition`: scrollTo와 유사한 지정된 좌표로 스크롤을 이동시키는 함수입니다. `ScrollToOptions`을 매개변수로 받습니다.\n * - `scrollToElement`: scrollIntoView와 유사한 지정된 요소로 스크롤을 이동시키는 함수입니다. `target` 요소와 `ScrollToElementOptions`을 매개변수로 받습니다.\n *\n * @example\n * ```tsx\n * // scrollToPosition를 사용하면 top, left와 같은 포지션 값을 기준으로 이동합니다.\n * const { containerRef, scrollToPosition } = useScrollTo<HTMLDivElement>();\n *\n * scrollToPosition({\n * top: 300,\n * left: 300,\n * behavior: 'smooth'\n * });\n *\n * <div ref={containerRef}>{...}</div>\n * //containerRef를 할당하지 않으면 window를 기반으로, 할당하면 해당 container를 기반으로 스크롤 합니다.\n * ```\n *\n * @example\n * ```tsx\n * // scrollToElement를 사용하면 첫 번째 인자로 넣은 타겟을 기준으로 스크롤합니다.\n * const target = useRef<HTMLDivElement | null>(null);\n * const { containerRef, scrollToElement } = useScrollTo<HTMLDivElement>();\n *\n * scrollToElement(target.current, {\n * offsetX: 300,\n * offsetY: 300,\n * alignY: 'start', // 세로 정렬, 'start' | 'center' | 'end'\n * alignX: 'start', // 가로 정렬, 'start' | 'center' | 'end'\n * behavior: 'smooth'\n * });\n *\n * <div ref={containerRef}>{...}</div>\n * //containerRef를 할당하지 않으면 window를 기반으로, 할당하면 해당 container를 기반으로 스크롤 합니다.\n * ```\n */\nexport function useScrollTo<T extends HTMLElement>(): UseScrollToReturnType<T> {\n const containerRef = useRef<T>(null);\n\n /**\n * @description scrollTo와 유사하게 동작합니다. containerRef를 할당하지 않으면 window를 기반으로 스크롤합니다.\n */\n const scrollToPosition = useCallback(\n (scrollToOptions: ScrollToOptions = {}) => {\n const { left = 0, top = 0, behavior = 'auto' } = scrollToOptions;\n\n const scrollElement = containerRef.current ?? window;\n\n scrollElement.scrollTo({\n left,\n top,\n behavior,\n });\n },\n []\n );\n\n /**\n * @description scrollIntoView와 유사하게 동작하지만, alignX/Y, offset을 옵션을 받을 수 있습니다.\n */\n const scrollToElement = useCallback(\n <E extends HTMLElement>(\n target: E,\n scrollToElementOptions: ScrollToElementOptions = {}\n ) => {\n if (!target) return;\n\n const scrollElement = containerRef.current ?? window;\n const { behavior = 'auto' } = scrollToElementOptions;\n\n const { left, top } = getRelativePosition(\n scrollElement,\n target,\n scrollToElementOptions\n );\n\n scrollElement.scrollTo({\n top,\n left,\n behavior,\n });\n },\n []\n );\n\n return { containerRef, scrollToPosition, scrollToElement };\n}\n"],"names":[],"mappings":"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"}