@modern-kit/react
Version:
99 lines (96 loc) • 4.79 kB
TypeScript
import React__default from 'react';
/**
* @description HTML 요소들의 태그 이름 타입 (예: "div", "span", "input" 등)
*/
type HTMLElementType = keyof JSX.IntrinsicElements;
/**
* @description React.DOMAttributes<HTMLElement>에 정의된 이벤트
* - "on"으로 시작하는 이벤트 핸들러 이름만 포함 (예: "onClick", "onChange", "onSubmit" 등)
*/
type EventNames = keyof React__default.DOMAttributes<HTMLElement> & `on${string}`;
/**
* @description 특정 HTML 요소의 특정 이벤트에 대한 이벤트 객체 타입을 추론하는 제네릭 타입
* @template K - HTML 요소 타입 (예: "button", "input" 등)
* @template E - 이벤트 핸들러 이름 (예: "onClick", "onChange" 등)
* @returns 해당 이벤트의 이벤트 객체 타입 또는 never
* @example
* type InputChangeEvent = ElementEventType<"input", "onChange">; // React.ChangeEvent<HTMLInputElement>
* type FormSubmitEvent = ElementEventType<"form", "onSubmit">; // React.FormEvent<HTMLFormElement>
* type ButtonClickEvent = ElementEventType<"button", "onClick">; // React.MouseEvent<HTMLButtonElement, MouseEvent>
*/
type ElementEventType<K extends HTMLElementType, E extends EventNames> = JSX.IntrinsicElements[K][E] extends ((e: infer Event) => void) | undefined ? Event : never;
interface EventExtenderProps<K extends HTMLElementType, E extends EventNames> {
children: JSX.Element;
capture: E;
shouldAwait?: boolean;
beforeEvent?: (e: ElementEventType<K, E>) => void | Promise<void>;
afterEvent?: (e: ElementEventType<K, E>) => void | Promise<void>;
}
/**
* @description 자식 컴포넌트의 이벤트 핸들러를 확장하여 `전후 처리`를 가능하게 하는 컴포넌트입니다.
*
* `shouldAwait` 옵션에 따라 다음과 같이 동작합니다:
*
* `shouldAwait: false` (기본값)
* - 비동기 함수를 await 하지 않습니다.
* - beforeEvent → 원본 이벤트 → afterEvent 순서로 실행되지만, 각 단계의 완료를 기다리지 않습니다.
* - 일반적인 이벤트 호출 순서를 유지합니다.
* - 예시: mouseDown -> mouseUp -> click 호출 순서가 유지됩니다.
*
* `shouldAwait: true`
* - 비동기 함수를 await 합니다.
* - beforeEvent → 원본 이벤트 → afterEvent 순서로 실행을 보장하며, 각 단계의 완료를 기다립니다.
* - 주의: 일반적인 이벤트 호출 순서와 달라질 수 있습니다.
* - 예시: `mouseUp` 이벤트는 `click` 이벤트 이전에 호출되는게 일반적이지만, `onMouseUp` 이벤트를 캡처하면 `mouseUp` 이벤트가 `click` 이벤트 이후에 호출됩니다.
*
* @template K - HTML 요소 타입 (예: "button", "input" 등)
* @template E - 이벤트 핸들러 이름 (예: "onClick", "onChange" 등)
* @param {EventExtenderProps<K, E>} props - 컴포넌트 속성
* @param {JSX.Element} props.children - 단일 자식 컴포넌트 (React 엘리먼트)
* @param {E} props.capture - 확장하고자 하는 이벤트 핸들러 이름
* @param {boolean} [props.shouldAwait=false] - 이벤트 핸들러의 비동기 함수를 await 할지 여부. true일 경우 각 핸들러의 완료를 기다립니다.
* @param {(e: ElementEventType<K, E>) => void | Promise<void>} [props.beforeEvent] - 이벤트 발생 전 실행할 함수, 비동기 함수 허용
* @param {(e: ElementEventType<K, E>) => void | Promise<void>} [props.afterEvent] - 이벤트 발생 후 실행할 함수, 비동기 함수 허용
* @returns {JSX.Element} 이벤트가 확장된 자식 컴포넌트
*
* @example
* ```tsx
* // 기본 사용법
* <EventExtender
* capture="onClick"
* beforeEvent={(e: React.MouseEvent<HTMLButtonElement>) => {
* console.log('클릭 전', e);
* }}
* afterEvent={(e: React.MouseEvent<HTMLButtonElement>) => {
* console.log('클릭 후', e);
* }}
* >
* <button onClick={(e) => console.log('클릭', e)}>
* Button
* </button>
* </EventExtender>
* ```
*
* @example
* ```tsx
* // 비동기 함수의 완료를 기다립니다.
* <EventExtender
* shouldAwait={true} // (*)
* capture="onClick"
* beforeEvent={async (e: React.MouseEvent<HTMLButtonElement>) => {
* console.log('클릭 전', e);
* await asyncFunction();
* }}
* afterEvent={async (e: React.MouseEvent<HTMLButtonElement>) => {
* console.log('클릭 후', e);
* await asyncFunction();
* }}
* >
* <button onClick={(e: React.MouseEvent<HTMLButtonElement>) => console.log('클릭', e)}>
* Button
* </button>
* </EventExtender>
* ```
*/
declare const EventExtender: <K extends HTMLElementType, E extends EventNames>({ children, capture, shouldAwait, beforeEvent, afterEvent, }: EventExtenderProps<K, E>) => JSX.Element;
export { EventExtender };