/** * V2 컴포넌트 간 통신 이벤트 타입 정의 * * 모든 V2 컴포넌트는 이 파일에 정의된 이벤트 타입을 사용해야 합니다. * 이벤트 발행/구독 시 타입 안전성을 보장합니다. */ // ============================================================ // 이벤트 상세 데이터 타입 (event.detail) // ============================================================ /** * 테이블 리스트 데이터 변경 이벤트 * 발행: v2-table-list * 구독: v2-aggregation-widget, v2-repeat-container */ export interface TableListDataChangeDetail { componentId: string; tableName: string; data: any[]; selectedRows: string[] | number[]; } /** * 리피터 데이터 변경 이벤트 * 발행: v2-unified-repeater * 구독: v2-aggregation-widget, v2-repeat-container */ export interface RepeaterDataChangeDetail { componentId: string; tableName: string; data: any[]; selectedData?: any[]; } /** * 폼 저장 전 이벤트 * 발행: buttonActions, UnifiedFormContext * 구독: v2-unified-repeater, simple-repeater-table, modal-repeater-table 등 */ export interface BeforeFormSaveDetail { formData: Record; skipDefaultSave?: boolean; } /** * 폼 저장 후 이벤트 * 발행: UnifiedFormContext * 구독: 저장 결과 처리 컴포넌트들 */ export interface AfterFormSaveDetail { success: boolean; data?: any; error?: string; } /** * 리피터 저장 이벤트 (마스터-디테일 FK 연결용) * 발행: InteractiveScreenViewerDynamic * 구독: v2-unified-repeater */ export interface RepeaterSaveDetail { parentId?: string | number; masterRecordId: string | number; mainFormData: Record; tableName: string; } /** * 테이블 새로고침 이벤트 * 발행: v2-button-primary, buttonActions * 구독: v2-table-list, v2-split-panel-layout */ export interface RefreshTableDetail { tableName?: string; componentId?: string; } /** * 카드 디스플레이 새로고침 이벤트 * 발행: buttonActions, InteractiveScreenViewerDynamic * 구독: v2-card-display */ export interface RefreshCardDisplayDetail { componentId?: string; } /** * 컴포넌트 간 데이터 전달 이벤트 * 발행: buttonActions * 구독: v2-unified-repeater */ export interface ComponentDataTransferDetail { sourceComponentId: string; targetComponentId: string; data: any[]; mode: "append" | "replace" | "merge"; mappingRules?: Array<{ sourceField: string; targetField: string; defaultValue?: any; }>; } /** * 분할 패널 간 데이터 전달 이벤트 * 발행: buttonActions * 구독: v2-unified-repeater, repeater-field-group */ export interface SplitPanelDataTransferDetail { sourcePosition: "left" | "right"; targetPosition: "left" | "right"; data: any[]; mode: "append" | "replace" | "merge"; mappingRules?: Array<{ sourceField: string; targetField: string; defaultValue?: any; }>; } /** * 연관 데이터 버튼 선택 이벤트 * 발행: related-data-buttons * 구독: v2-table-list */ export interface RelatedButtonSelectDetail { targetTable: string; filterColumn: string; filterValue: any; selectedData?: any; } /** * 모달 제어 이벤트 */ export interface EditModalDetail { screenId?: number; recordId?: string | number; data?: any; } // ============================================================ // 이벤트 이름 상수 // ============================================================ export const V2_EVENTS = { // 데이터 변경 이벤트 TABLE_LIST_DATA_CHANGE: "tableListDataChange", REPEATER_DATA_CHANGE: "repeaterDataChange", // 폼 저장 이벤트 BEFORE_FORM_SAVE: "beforeFormSave", AFTER_FORM_SAVE: "afterFormSave", REPEATER_SAVE: "repeaterSave", // UI 갱신 이벤트 REFRESH_TABLE: "refreshTable", REFRESH_CARD_DISPLAY: "refreshCardDisplay", // 데이터 전달 이벤트 COMPONENT_DATA_TRANSFER: "componentDataTransfer", SPLIT_PANEL_DATA_TRANSFER: "splitPanelDataTransfer", // 모달 제어 이벤트 OPEN_EDIT_MODAL: "openEditModal", CLOSE_EDIT_MODAL: "closeEditModal", SAVE_SUCCESS_IN_MODAL: "saveSuccessInModal", // 연관 데이터 버튼 이벤트 RELATED_BUTTON_SELECT: "related-button-select", RELATED_BUTTON_REGISTER: "related-button-register", RELATED_BUTTON_UNREGISTER: "related-button-unregister", } as const; // ============================================================ // Window EventMap 확장 (타입 안전한 이벤트 리스너) // ============================================================ declare global { interface WindowEventMap { // 데이터 변경 이벤트 [V2_EVENTS.TABLE_LIST_DATA_CHANGE]: CustomEvent; [V2_EVENTS.REPEATER_DATA_CHANGE]: CustomEvent; // 폼 저장 이벤트 [V2_EVENTS.BEFORE_FORM_SAVE]: CustomEvent; [V2_EVENTS.AFTER_FORM_SAVE]: CustomEvent; [V2_EVENTS.REPEATER_SAVE]: CustomEvent; // UI 갱신 이벤트 [V2_EVENTS.REFRESH_TABLE]: CustomEvent; [V2_EVENTS.REFRESH_CARD_DISPLAY]: CustomEvent; // 데이터 전달 이벤트 [V2_EVENTS.COMPONENT_DATA_TRANSFER]: CustomEvent; [V2_EVENTS.SPLIT_PANEL_DATA_TRANSFER]: CustomEvent; // 연관 데이터 버튼 이벤트 [V2_EVENTS.RELATED_BUTTON_SELECT]: CustomEvent; } } // ============================================================ // 유틸리티 함수 // ============================================================ /** * 타입 안전한 이벤트 발행 함수 */ export function dispatchV2Event( eventName: K, detail: WindowEventMap[K] extends CustomEvent ? D : never ): void { if (typeof window !== "undefined") { window.dispatchEvent(new CustomEvent(eventName, { detail })); } } /** * 타입 안전한 이벤트 구독 함수 */ export function subscribeV2Event( eventName: K, handler: (event: WindowEventMap[K]) => void ): () => void { if (typeof window === "undefined") { return () => {}; } window.addEventListener(eventName, handler as EventListener); return () => { window.removeEventListener(eventName, handler as EventListener); }; } // ============================================================ // 내보내기 // ============================================================ export type V2EventName = typeof V2_EVENTS[keyof typeof V2_EVENTS];