/** * Unified 컴포넌트 타입 정의 * * 10개의 통합 컴포넌트 시스템을 위한 타입 정의 * - UnifiedInput * - UnifiedSelect * - UnifiedDate * - UnifiedText * - UnifiedMedia * - UnifiedList * - UnifiedLayout * - UnifiedGroup * - UnifiedBiz * - UnifiedHierarchy */ import { Position, Size, CommonStyle, ValidationRule } from "./unified-core"; // ===== 공통 타입 ===== /** * Unified 컴포넌트 타입 */ export type UnifiedComponentType = | "UnifiedInput" | "UnifiedSelect" | "UnifiedDate" | "UnifiedText" | "UnifiedMedia" | "UnifiedList" | "UnifiedLayout" | "UnifiedGroup" | "UnifiedBiz" | "UnifiedHierarchy"; /** * 조건부 렌더링 설정 */ export interface ConditionalConfig { enabled: boolean; field: string; // 참조 필드 operator: "=" | "!=" | ">" | "<" | "in" | "notIn" | "isEmpty" | "isNotEmpty"; value: unknown; action: "show" | "hide" | "disable" | "enable"; } /** * 자동 입력 설정 */ export interface AutoFillConfig { enabled: boolean; sourceTable: string; filterColumn: string; userField: "companyCode" | "userId" | "deptCode"; displayColumn: string; } /** * 연쇄 관계 설정 */ export interface CascadingConfig { parentField: string; filterColumn: string; clearOnChange?: boolean; } /** * 상호 배제 설정 */ export interface MutualExclusionConfig { enabled: boolean; targetField: string; type: "exclusive" | "inclusive"; } /** * 공통 Unified 컴포넌트 속성 */ export interface UnifiedBaseProps { id: string; label?: string; required?: boolean; readonly?: boolean; disabled?: boolean; // 데이터 바인딩 tableName?: string; columnName?: string; // 위치 및 크기 position?: Position; size?: Size; // 스타일 style?: CommonStyle; // 조건부 및 자동화 conditional?: ConditionalConfig; autoFill?: AutoFillConfig; // 유효성 검사 validation?: ValidationRule[]; } // ===== UnifiedInput ===== export type UnifiedInputType = "text" | "number" | "password" | "slider" | "color" | "button"; export type UnifiedInputFormat = "none" | "email" | "tel" | "url" | "currency" | "biz_no"; export interface UnifiedInputConfig { type: UnifiedInputType; format?: UnifiedInputFormat; mask?: string; placeholder?: string; // 숫자 전용 min?: number; max?: number; step?: number; // 버튼 전용 buttonText?: string; buttonVariant?: "default" | "destructive" | "outline" | "secondary" | "ghost"; onClick?: () => void; } export interface UnifiedInputProps extends UnifiedBaseProps { unifiedType: "UnifiedInput"; config: UnifiedInputConfig; value?: string | number; onChange?: (value: string | number) => void; } // ===== UnifiedSelect ===== export type UnifiedSelectMode = "dropdown" | "radio" | "check" | "tag" | "toggle" | "swap"; export type UnifiedSelectSource = "static" | "code" | "db" | "api" | "entity" | "category"; export interface SelectOption { value: string; label: string; } export interface UnifiedSelectConfig { mode: UnifiedSelectMode; source: UnifiedSelectSource; // 정적 옵션 (source: static) options?: SelectOption[]; // 코드 그룹 (source: code) codeGroup?: string; // DB 연결 (source: db) table?: string; valueColumn?: string; labelColumn?: string; filters?: Array<{ column: string; operator: string; value: unknown }>; // 엔티티 연결 (source: entity) entityTable?: string; entityValueField?: string; entityLabelField?: string; entityValueColumn?: string; // alias for entityValueField entityLabelColumn?: string; // alias for entityLabelField // API 연결 (source: api) apiEndpoint?: string; // 카테고리 연결 (source: category) - 레거시, code로 자동 변환됨 categoryTable?: string; categoryColumn?: string; // 공통 옵션 searchable?: boolean; multiple?: boolean; maxSelect?: number; allowClear?: boolean; // 연쇄 관계 cascading?: CascadingConfig; // 상호 배제 mutualExclusion?: MutualExclusionConfig; // 계층 코드 연쇄 선택 (source: code일 때 계층 구조 사용) hierarchical?: boolean; // 계층 구조 사용 여부 parentField?: string; // 부모 값을 참조할 필드 (다른 컴포넌트의 columnName) } export interface UnifiedSelectProps extends UnifiedBaseProps { unifiedType: "UnifiedSelect"; config: UnifiedSelectConfig; value?: string | string[]; onChange?: (value: string | string[]) => void; } // ===== UnifiedDate ===== export type UnifiedDateType = "date" | "time" | "datetime"; export interface UnifiedDateConfig { type: UnifiedDateType; format?: string; range?: boolean; minDate?: string; maxDate?: string; showToday?: boolean; } export interface UnifiedDateProps extends UnifiedBaseProps { unifiedType: "UnifiedDate"; config: UnifiedDateConfig; value?: string | [string, string]; // 범위 선택 시 튜플 onChange?: (value: string | [string, string]) => void; } // ===== UnifiedText ===== export type UnifiedTextMode = "simple" | "rich" | "code" | "markdown"; export interface UnifiedTextConfig { mode: UnifiedTextMode; rows?: number; maxLength?: number; placeholder?: string; resize?: "none" | "vertical" | "horizontal" | "both"; } export interface UnifiedTextProps extends UnifiedBaseProps { unifiedType: "UnifiedText"; config: UnifiedTextConfig; value?: string; onChange?: (value: string) => void; } // ===== UnifiedMedia ===== export type UnifiedMediaType = "file" | "image" | "video" | "audio"; export interface UnifiedMediaConfig { type: UnifiedMediaType; multiple?: boolean; accept?: string; maxSize?: number; preview?: boolean; uploadEndpoint?: string; } export interface UnifiedMediaProps extends UnifiedBaseProps { unifiedType: "UnifiedMedia"; config: UnifiedMediaConfig; value?: string | string[]; // 파일 URL 또는 배열 onChange?: (value: string | string[]) => void; } // ===== UnifiedList ===== export type UnifiedListViewMode = "table" | "card" | "kanban" | "list"; export interface ListColumn { field: string; header: string; width?: number; sortable?: boolean; filterable?: boolean; editable?: boolean; format?: string; } export interface UnifiedListCardConfig { titleColumn?: string; subtitleColumn?: string; descriptionColumn?: string; imageColumn?: string; cardsPerRow?: number; cardSpacing?: number; showActions?: boolean; } export interface UnifiedListConfig { viewMode: UnifiedListViewMode; editable?: boolean; searchable?: boolean; pageable?: boolean; pageSize?: number; columns?: ListColumn[]; modal?: boolean; cardConfig?: UnifiedListCardConfig; // 데이터 소스 dataSource?: { table?: string; api?: string; filters?: Array<{ column: string; operator: string; value: unknown }>; }; } export interface UnifiedListProps extends UnifiedBaseProps { unifiedType: "UnifiedList"; config: UnifiedListConfig; data?: Record[]; selectedRows?: Record[]; onRowSelect?: (rows: Record[]) => void; onRowClick?: (row: Record) => void; } // ===== UnifiedLayout ===== export type UnifiedLayoutType = "grid" | "split" | "flex" | "divider" | "screen-embed"; export interface UnifiedLayoutConfig { type: UnifiedLayoutType; columns?: number; // 12컬럼 시스템에서 실제 표시할 컬럼 수 (1-12) gap?: string; splitRatio?: number[]; direction?: "horizontal" | "vertical"; use12Column?: boolean; // 12컬럼 시스템 사용 여부 (기본 true) // screen-embed 전용 screenId?: number; } export interface UnifiedLayoutProps extends UnifiedBaseProps { unifiedType: "UnifiedLayout"; config: UnifiedLayoutConfig; children?: React.ReactNode; } // ===== UnifiedGroup ===== export type UnifiedGroupType = "tabs" | "accordion" | "section" | "card-section" | "modal" | "form-modal"; export interface TabItem { id: string; title: string; content?: React.ReactNode; } export interface UnifiedGroupConfig { type: UnifiedGroupType; title?: string; collapsible?: boolean; defaultExpanded?: boolean; // 탭 전용 tabs?: TabItem[]; activeTab?: string; // 모달 전용 modalSize?: "sm" | "md" | "lg" | "xl"; } export interface UnifiedGroupProps extends UnifiedBaseProps { unifiedType: "UnifiedGroup"; config: UnifiedGroupConfig; children?: React.ReactNode; open?: boolean; onOpenChange?: (open: boolean) => void; } // ===== UnifiedBiz ===== export type UnifiedBizType = "flow" | "rack" | "map" | "numbering" | "category" | "mapping" | "related-buttons"; export interface UnifiedBizConfig { type: UnifiedBizType; // 각 타입별 설정은 제네릭하게 처리 config?: Record; } export interface UnifiedBizProps extends UnifiedBaseProps { unifiedType: "UnifiedBiz"; config: UnifiedBizConfig; } // ===== UnifiedHierarchy ===== export type UnifiedHierarchyType = "tree" | "org" | "bom" | "cascading"; export type UnifiedHierarchyViewMode = "tree" | "table" | "indent" | "dropdown"; export interface HierarchyNode { id: string; parentId?: string; label: string; children?: HierarchyNode[]; data?: Record; } export interface UnifiedHierarchyConfig { type: UnifiedHierarchyType; viewMode: UnifiedHierarchyViewMode; source?: string; // 계층 그룹 코드 editable?: boolean; draggable?: boolean; showQty?: boolean; // BOM 전용 maxLevel?: number; } export interface UnifiedHierarchyProps extends UnifiedBaseProps { unifiedType: "UnifiedHierarchy"; config: UnifiedHierarchyConfig; data?: HierarchyNode[]; selectedNode?: HierarchyNode; onNodeSelect?: (node: HierarchyNode) => void; onNodeMove?: (nodeId: string, newParentId: string) => void; } // ===== 통합 Props 유니온 타입 ===== export type UnifiedComponentProps = | UnifiedInputProps | UnifiedSelectProps | UnifiedDateProps | UnifiedTextProps | UnifiedMediaProps | UnifiedListProps | UnifiedLayoutProps | UnifiedGroupProps | UnifiedBizProps | UnifiedHierarchyProps; // ===== 타입 가드 ===== export function isUnifiedInput(props: UnifiedComponentProps): props is UnifiedInputProps { return props.unifiedType === "UnifiedInput"; } export function isUnifiedSelect(props: UnifiedComponentProps): props is UnifiedSelectProps { return props.unifiedType === "UnifiedSelect"; } export function isUnifiedDate(props: UnifiedComponentProps): props is UnifiedDateProps { return props.unifiedType === "UnifiedDate"; } export function isUnifiedText(props: UnifiedComponentProps): props is UnifiedTextProps { return props.unifiedType === "UnifiedText"; } export function isUnifiedMedia(props: UnifiedComponentProps): props is UnifiedMediaProps { return props.unifiedType === "UnifiedMedia"; } export function isUnifiedList(props: UnifiedComponentProps): props is UnifiedListProps { return props.unifiedType === "UnifiedList"; } export function isUnifiedLayout(props: UnifiedComponentProps): props is UnifiedLayoutProps { return props.unifiedType === "UnifiedLayout"; } export function isUnifiedGroup(props: UnifiedComponentProps): props is UnifiedGroupProps { return props.unifiedType === "UnifiedGroup"; } export function isUnifiedBiz(props: UnifiedComponentProps): props is UnifiedBizProps { return props.unifiedType === "UnifiedBiz"; } export function isUnifiedHierarchy(props: UnifiedComponentProps): props is UnifiedHierarchyProps { return props.unifiedType === "UnifiedHierarchy"; } // ===== JSON Schema 타입 ===== export interface JSONSchemaProperty { type: "string" | "number" | "boolean" | "array" | "object"; title?: string; description?: string; enum?: string[]; default?: unknown; items?: JSONSchemaProperty; properties?: Record; required?: string[]; } export interface UnifiedConfigSchema { type: "object"; properties: Record; required?: string[]; } // ===== 레거시 컴포넌트 → Unified 컴포넌트 매핑 ===== export const LEGACY_TO_UNIFIED_MAP: Record = { // Input 계열 "text-input": "UnifiedInput", "number-input": "UnifiedInput", "password-input": "UnifiedInput", // Select 계열 "select-basic": "UnifiedSelect", "radio-basic": "UnifiedSelect", "checkbox-basic": "UnifiedSelect", "entity-search-input": "UnifiedSelect", "autocomplete-search-input": "UnifiedSelect", // Date 계열 "date-input": "UnifiedDate", // Text 계열 "textarea-basic": "UnifiedText", // Media 계열 "file-upload": "UnifiedMedia", "image-widget": "UnifiedMedia", // List 계열 "table-list": "UnifiedList", "table-search-widget": "UnifiedList", "modal-repeater-table": "UnifiedList", "repeater-field-group": "UnifiedList", "card-display": "UnifiedList", // Layout 계열 "split-panel-layout": "UnifiedLayout", "screen-split-panel": "UnifiedLayout", // Group 계열 "tabs-widget": "UnifiedGroup", "section-paper": "UnifiedGroup", "section-card": "UnifiedGroup", "universal-form-modal": "UnifiedGroup", // Biz 계열 "category-manager": "UnifiedBiz", "numbering-rule": "UnifiedBiz", "flow-widget": "UnifiedBiz", // Button (Input의 버튼 모드) "button-primary": "UnifiedInput", };