1aa48cc0bb
## 디자인 개편 - IDE 톤 CSS 오버라이드 (builder-ide.css) - 컴팩트화 (폰트/간격/패딩 축소) - INVYONE STUDIO 로고 추가 (SlimToolbar) - 좌측 수평 탭 → 수직 아코디언 (details/summary) - 우측 속성 패널 신설 (V2PropertiesPanel 완전 이주) - 다크모드 지원 (7개 통합 컴포넌트 inline hex → CSS 변수) ## 기반 시스템 - ScreenDefinition.fields/connections 타입 확장 - ComponentDefinition.dataPorts 타입 확장 - FieldConfig adapters (fieldsToColumns/Search/Form) - DataPortBus + setupConnections runtime - FieldsPanel (화면 수준 필드 관리 패널) ## 컴포넌트 통합 (Phase A~C) - divider (3→1): 가로/세로 + 텍스트 구분선 - title (2→1): h1~h6/body/caption variant - button (3→1): 6 variant × 13 actionType - search (3→1): inline/stacked 검색 필터 - input (20+→1): FieldConfig.type 10종 내부 분기 - stats (6→1): card/chip/bigNumber 3종 스타일 - table (9→1): table/split/grouped/pivot/card 5종 displayMode - container (11→1): tabs/section/accordion/repeater/conditional 5종 ## 버그 수정 (기존 VEX 코드) - 드래그 드롭 불가 (defaultSize camelCase 불일치) - 설정 변경 미반영 (componentConfig vs component_config) - ConfigPanel 미인식 (config_panel vs configPanel) - v2- 자동 매핑 함정 (INVYONE_UNIFIED_IDS 화이트리스트) - LayerManagerPanel 무한 API 호출 (useEffect deps) - Button size 이름 충돌 (visual size 객체 vs config string) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
396 lines
12 KiB
TypeScript
396 lines
12 KiB
TypeScript
/**
|
|
* 컴포넌트 시스템 타입 정의
|
|
* 레이아웃 시스템과 동일한 패턴으로 설계된 새로운 컴포넌트 관리 시스템
|
|
*/
|
|
|
|
import React from "react";
|
|
import type { WebType, AutoGenerationConfig } from "./screen";
|
|
import type { DataPort } from "./invyone-component";
|
|
|
|
/**
|
|
* 컴포넌트 카테고리 열거형
|
|
* 기존의 하드코딩된 카테고리를 타입 안전한 enum으로 대체
|
|
*/
|
|
export enum ComponentCategory {
|
|
UI = "ui", // 기본 UI 컴포넌트 (버튼, 입력 등)
|
|
INPUT = "input", // 입력 컴포넌트 (텍스트, 셀렉트, 체크박스 등)
|
|
DISPLAY = "display", // 표시 컴포넌트 (라벨, 이미지, 아이콘 등)
|
|
ACTION = "action", // 액션 컴포넌트 (버튼, 링크 등)
|
|
LAYOUT = "layout", // 레이아웃 컴포넌트 (컨테이너, 그룹 등)
|
|
DATA = "data", // 데이터 컴포넌트 (테이블, 리스트 등)
|
|
CHART = "chart", // 차트 컴포넌트 (그래프, 차트 등)
|
|
FORM = "form", // 폼 컴포넌트 (폼 그룹, 필드셋 등)
|
|
MEDIA = "media", // 미디어 컴포넌트 (이미지, 비디오 등)
|
|
NAVIGATION = "navigation", // 네비게이션 컴포넌트 (메뉴, 탭 등)
|
|
FEEDBACK = "feedback", // 피드백 컴포넌트 (알림, 토스트 등)
|
|
UTILITY = "utility", // 유틸리티 컴포넌트 (로딩, 스피너 등)
|
|
CONTAINER = "container", // 컨테이너 컴포넌트 (패널, 카드 등)
|
|
SYSTEM = "system", // 시스템 컴포넌트 (에러 바운더리 등)
|
|
ADMIN = "admin", // 관리자 전용 컴포넌트
|
|
CUSTOM = "custom", // 커스텀 컴포넌트
|
|
V2 = "v2", // 통합 컴포넌트 (새로운 V2 컴포넌트 시스템)
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 설정 인터페이스
|
|
* 각 컴포넌트의 고유한 설정값들을 타입 안전하게 관리
|
|
*/
|
|
export interface ComponentConfig {
|
|
[key: string]: any;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 크기 정의
|
|
*/
|
|
export interface ComponentSize {
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
// screen.ts에서 자동생성 관련 타입들을 import
|
|
export type { AutoGenerationType, AutoGenerationConfig } from "./screen";
|
|
|
|
/**
|
|
* 컴포넌트 렌더러 Props
|
|
* 모든 컴포넌트 렌더러가 받는 공통 Props
|
|
*/
|
|
export interface ComponentRendererProps {
|
|
component: any; // ComponentData from screen.ts
|
|
isDesignMode?: boolean;
|
|
isSelected?: boolean;
|
|
isInteractive?: boolean;
|
|
onClick?: () => void;
|
|
onDragStart?: (e: React.DragEvent) => void;
|
|
onDragEnd?: (e: React.DragEvent) => void;
|
|
onUpdate?: (updates: Partial<any>) => void;
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
form_data?: Record<string, any>;
|
|
onFormDataChange?: (fieldName: string, value: any) => void;
|
|
|
|
// 새로운 기능들
|
|
auto_generation?: AutoGenerationConfig; // 자동생성 설정
|
|
hidden?: boolean; // 숨김 기능 (편집기에서는 연하게, 실제 화면에서는 숨김)
|
|
|
|
// 설정 변경 핸들러
|
|
onConfigChange?: (config: any) => void;
|
|
|
|
[key: string]: any;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 렌더러 클래스 인터페이스
|
|
*/
|
|
export interface ComponentRendererClass {
|
|
new (props: ComponentRendererProps): {
|
|
render(): React.ReactElement;
|
|
};
|
|
componentDefinition: ComponentDefinition;
|
|
registerSelf(): void;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 정의 인터페이스
|
|
* 각 컴포넌트의 메타데이터와 설정을 담는 핵심 인터페이스
|
|
*/
|
|
export interface ComponentDefinition {
|
|
// 기본 정보
|
|
id: string; // 고유 ID (kebab-case)
|
|
name: string; // 한글 표시명
|
|
name_eng?: string; // 영문명
|
|
description: string; // 설명
|
|
|
|
// 분류 및 타입
|
|
category: ComponentCategory; // 카테고리 (enum)
|
|
web_type: WebType; // 웹 타입 (기존 WebType 재사용)
|
|
|
|
// React 컴포넌트
|
|
component: React.ComponentType<any>; // 실제 React 컴포넌트
|
|
renderer?: ComponentRendererClass; // 렌더러 클래스 (선택사항)
|
|
|
|
// 설정
|
|
default_config: ComponentConfig; // 기본 설정값
|
|
default_size: ComponentSize; // 기본 크기
|
|
config_panel?: React.ComponentType<any>; // 설정 패널 컴포넌트
|
|
|
|
// UI 요소
|
|
icon?: React.ComponentType | string; // 아이콘 (컴포넌트 또는 문자열)
|
|
preview_image?: string; // 미리보기 이미지 URL
|
|
|
|
// 메타데이터
|
|
tags?: string[]; // 검색용 태그
|
|
version?: string; // 버전
|
|
author?: string; // 작성자
|
|
documentation?: string; // 문서 URL
|
|
|
|
// 검증 및 제약
|
|
validation?: ComponentValidation; // 유효성 검사 규칙
|
|
dependencies?: string[]; // 의존성 컴포넌트 ID
|
|
|
|
// 표시 설정
|
|
hidden?: boolean; // 팔레트에서 숨김 여부
|
|
|
|
// 생성 정보
|
|
created_at?: Date; // 생성일
|
|
updated_at?: Date; // 수정일
|
|
|
|
// ─── INVYONE 확장 (Phase 1+) ───
|
|
/** 컴포넌트 간 통신용 데이터 포트. 빌더에서 시각적 연결 시 사용. */
|
|
dataPorts?: {
|
|
inputs?: DataPort[];
|
|
outputs?: DataPort[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 유효성 검사 규칙
|
|
*/
|
|
export interface ComponentValidation {
|
|
required?: string[]; // 필수 속성들
|
|
min_size?: ComponentSize; // 최소 크기
|
|
max_size?: ComponentSize; // 최대 크기
|
|
allowed_parents?: string[]; // 허용되는 부모 컴포넌트 타입
|
|
allowed_children?: string[]; // 허용되는 자식 컴포넌트 타입
|
|
max_length?: { [field: string]: number }; // 필드별 최대 길이
|
|
pattern?: { [field: string]: RegExp }; // 필드별 정규식 패턴
|
|
custom?: (component: any) => string | null; // 커스텀 검증 함수
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 레지스트리 이벤트
|
|
*/
|
|
export interface ComponentRegistryEvent {
|
|
type: "component_registered" | "component_unregistered" | "component_updated";
|
|
data: ComponentDefinition;
|
|
timestamp: Date;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 검색 옵션
|
|
*/
|
|
export interface ComponentSearchOptions {
|
|
query?: string; // 검색어
|
|
category?: ComponentCategory; // 카테고리 필터
|
|
web_type?: WebType; // 웹타입 필터
|
|
tags?: string[]; // 태그 필터
|
|
author?: string; // 작성자 필터
|
|
limit?: number; // 결과 제한
|
|
offset?: number; // 시작 위치
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 통계 정보
|
|
*/
|
|
export interface ComponentStats {
|
|
total: number; // 전체 컴포넌트 수
|
|
by_category: Array<{
|
|
// 카테고리별 통계
|
|
category: ComponentCategory;
|
|
count: number;
|
|
}>;
|
|
by_web_type: Array<{
|
|
// 웹타입별 통계
|
|
web_type: WebType;
|
|
count: number;
|
|
}>;
|
|
by_author: Array<{
|
|
// 작성자별 통계
|
|
author: string;
|
|
count: number;
|
|
}>;
|
|
recently_added: ComponentDefinition[]; // 최근 추가된 컴포넌트
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 자동 발견 옵션
|
|
*/
|
|
export interface ComponentAutoDiscoveryOptions {
|
|
pattern?: string; // 파일 패턴
|
|
base_dir?: string; // 기본 디렉토리
|
|
verbose?: boolean; // 상세 로그
|
|
continue_on_error?: boolean; // 오류 시 계속 진행
|
|
timeout?: number; // 타임아웃 (ms)
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 자동 발견 결과
|
|
*/
|
|
export interface ComponentDiscoveryResult {
|
|
success: boolean; // 성공 여부
|
|
components_found: number; // 발견된 컴포넌트 수
|
|
components_loaded: number; // 로드된 컴포넌트 수
|
|
errors: Error[]; // 발생한 오류들
|
|
duration: number; // 소요 시간 (ms)
|
|
details: ComponentModuleInfo[]; // 상세 정보
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 모듈 정보
|
|
*/
|
|
export interface ComponentModuleInfo {
|
|
path: string; // 파일 경로
|
|
id: string; // 컴포넌트 ID
|
|
name: string; // 컴포넌트 이름
|
|
loaded: boolean; // 로드 여부
|
|
error?: Error; // 오류 (있는 경우)
|
|
timestamp: number; // 타임스탬프
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 생성 옵션 (CLI용)
|
|
*/
|
|
export interface CreateComponentOptions {
|
|
id: string; // 컴포넌트 ID
|
|
name: string; // 컴포넌트 이름
|
|
name_eng?: string; // 영문명
|
|
description: string; // 설명
|
|
category: ComponentCategory; // 카테고리
|
|
web_type: WebType; // 웹타입
|
|
default_size: ComponentSize; // 기본 크기
|
|
author?: string; // 작성자
|
|
tags?: string[]; // 태그
|
|
icon?: string; // 아이콘
|
|
template?: string; // 템플릿 이름
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 마이그레이션 옵션
|
|
*/
|
|
export interface ComponentMigrationOptions {
|
|
component_code: string; // 기존 컴포넌트 코드
|
|
new_id: string; // 새 컴포넌트 ID
|
|
preserve_config?: boolean; // 설정 보존 여부
|
|
update_references?: boolean; // 참조 업데이트 여부
|
|
dry_run?: boolean; // 테스트 실행 여부
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 정의 생성 헬퍼 함수의 옵션
|
|
*/
|
|
export interface CreateComponentDefinitionOptions {
|
|
id: string;
|
|
name: string;
|
|
name_eng?: string;
|
|
description: string;
|
|
category: ComponentCategory;
|
|
web_type: WebType;
|
|
component: React.ComponentType<any>;
|
|
renderer?: ComponentRendererClass;
|
|
default_config?: ComponentConfig;
|
|
default_size: ComponentSize;
|
|
config_panel?: React.ComponentType<any>;
|
|
icon?: React.ComponentType | string;
|
|
preview_image?: string;
|
|
tags?: string[];
|
|
version?: string;
|
|
author?: string;
|
|
documentation?: string;
|
|
validation?: ComponentValidation;
|
|
dependencies?: string[];
|
|
hidden?: boolean; // 팔레트에서 숨김 여부
|
|
// ─── INVYONE 확장 ───
|
|
/** 컴포넌트 간 통신용 데이터 포트 선언 (Phase 1+) */
|
|
dataPorts?: {
|
|
inputs?: DataPort[];
|
|
outputs?: DataPort[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 유틸리티 타입들
|
|
*/
|
|
export type ComponentId = string;
|
|
export type ComponentName = string;
|
|
export type ComponentCategoryKey = keyof typeof ComponentCategory;
|
|
|
|
/**
|
|
* 기본 상수들
|
|
*/
|
|
export const DEFAULT_COMPONENT_SIZE: ComponentSize = {
|
|
width: 200,
|
|
height: 36,
|
|
};
|
|
|
|
export const COMPONENT_CATEGORIES_INFO = {
|
|
[ComponentCategory.UI]: {
|
|
name: "UI",
|
|
description: "기본 UI 컴포넌트",
|
|
color: "#3b82f6",
|
|
},
|
|
[ComponentCategory.INPUT]: {
|
|
name: "입력",
|
|
description: "사용자 입력을 받는 컴포넌트",
|
|
color: "#10b981",
|
|
},
|
|
[ComponentCategory.DISPLAY]: {
|
|
name: "표시",
|
|
description: "정보를 표시하는 컴포넌트",
|
|
color: "#f59e0b",
|
|
},
|
|
[ComponentCategory.ACTION]: {
|
|
name: "액션",
|
|
description: "사용자 동작을 처리하는 컴포넌트",
|
|
color: "#ef4444",
|
|
},
|
|
[ComponentCategory.LAYOUT]: {
|
|
name: "레이아웃",
|
|
description: "화면 구조를 제공하는 컴포넌트",
|
|
color: "#8b5cf6",
|
|
},
|
|
[ComponentCategory.CHART]: {
|
|
name: "차트",
|
|
description: "데이터 시각화 컴포넌트",
|
|
color: "#212121",
|
|
},
|
|
[ComponentCategory.FORM]: {
|
|
name: "폼",
|
|
description: "폼 관련 컴포넌트",
|
|
color: "#84cc16",
|
|
},
|
|
[ComponentCategory.MEDIA]: {
|
|
name: "미디어",
|
|
description: "이미지, 비디오 등 미디어 컴포넌트",
|
|
color: "#f97316",
|
|
},
|
|
[ComponentCategory.NAVIGATION]: {
|
|
name: "네비게이션",
|
|
description: "화면 이동을 도와주는 컴포넌트",
|
|
color: "#6366f1",
|
|
},
|
|
[ComponentCategory.FEEDBACK]: {
|
|
name: "피드백",
|
|
description: "사용자 피드백을 제공하는 컴포넌트",
|
|
color: "#ec4899",
|
|
},
|
|
[ComponentCategory.UTILITY]: {
|
|
name: "유틸리티",
|
|
description: "보조 기능 컴포넌트",
|
|
color: "#6b7280",
|
|
},
|
|
[ComponentCategory.CONTAINER]: {
|
|
name: "컨테이너",
|
|
description: "다른 컴포넌트를 담는 컨테이너",
|
|
color: "#212121",
|
|
},
|
|
[ComponentCategory.SYSTEM]: {
|
|
name: "시스템",
|
|
description: "시스템 관련 컴포넌트",
|
|
color: "#1f2937",
|
|
},
|
|
[ComponentCategory.ADMIN]: {
|
|
name: "관리",
|
|
description: "관리자 전용 컴포넌트",
|
|
color: "#7c2d12",
|
|
},
|
|
[ComponentCategory.CUSTOM]: {
|
|
name: "커스텀",
|
|
description: "사용자 정의 컴포넌트",
|
|
color: "#059669",
|
|
},
|
|
[ComponentCategory.V2]: {
|
|
name: "통합",
|
|
description: "새로운 통합 컴포넌트 시스템",
|
|
color: "#2563eb",
|
|
},
|
|
} as const;
|