docs: 다양한 문서 및 가이드 업데이트

- 여러 문서의 내용을 업데이트하여 최신 정보를 반영하였습니다.
- 컴포넌트 개발 가이드와 관련된 문서의 목차를 재구성하고, V2 및 Zod 레이아웃 시스템에 대한 내용을 추가하였습니다.
- 화면 컴포넌트 개발 가이드를 개선하여 핵심 원칙과 패턴을 명확히 설명하였습니다.
- 불필요한 문서 및 가이드를 삭제하고, 통합된 가이드를 통해 개발자들이 쉽게 참고할 수 있도록 하였습니다.
This commit is contained in:
kjs
2026-01-28 17:36:19 +09:00
parent e0ee375f01
commit 95bef976a5
276 changed files with 2544 additions and 2495 deletions

View File

@@ -6,22 +6,22 @@ import { DynamicLayoutRenderer } from "./DynamicLayoutRenderer";
import { ComponentRegistry } from "./ComponentRegistry";
import { filterDOMProps } from "@/lib/utils/domPropsFilter";
// Unified 컴포넌트 import
// V2 컴포넌트 import
import {
UnifiedInput,
UnifiedSelect,
UnifiedDate,
UnifiedList,
UnifiedLayout,
UnifiedGroup,
UnifiedMedia,
UnifiedBiz,
UnifiedHierarchy,
} from "@/components/unified";
import { UnifiedRepeater } from "@/components/unified/UnifiedRepeater";
V2Input,
V2Select,
V2Date,
V2List,
V2Layout,
V2Group,
V2Media,
V2Biz,
V2Hierarchy,
} from "@/components/v2";
import { V2Repeater } from "@/components/v2/V2Repeater";
// 통합 폼 시스템 import
import { useUnifiedFormOptional } from "@/components/unified/UnifiedFormContext";
import { useV2FormOptional } from "@/components/v2/V2FormContext";
// 컴포넌트 렌더러 인터페이스
export interface ComponentRenderer {
@@ -192,8 +192,8 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
// 🆕 레거시 타입을 v2 컴포넌트로 매핑 (v2 컴포넌트가 없으면 원본 유지)
const mapToV2ComponentType = (type: string | undefined): string | undefined => {
if (!type) return type;
// 이미 v2- 또는 unified- 접두사가 있으면 그대로 반환
if (type.startsWith("v2-") || type.startsWith("unified-")) return type;
// 이미 v2- 또는 v2- 접두사가 있으면 그대로 반환
if (type.startsWith("v2-") || type.startsWith("v2-")) return type;
// 레거시 타입을 v2로 매핑 시도
const v2Type = `v2-${type}`;
// v2 버전이 등록되어 있는지 확인
@@ -208,26 +208,26 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
// 컴포넌트 타입 변환 완료
// 🆕 Unified 폼 시스템 연동 (최상위에서 한 번만 호출)
// 🆕 V2 폼 시스템 연동 (최상위에서 한 번만 호출)
// eslint-disable-next-line react-hooks/rules-of-hooks
const unifiedFormContextForUnified = useUnifiedFormOptional();
const v2FormContextLocal = useV2FormOptional();
// 🆕 Unified 컴포넌트 처리
if (componentType?.startsWith("unified-")) {
const unifiedType = componentType as string;
// 🆕 V2 컴포넌트 처리
if (componentType?.startsWith("v2-")) {
const v2Type = componentType as string;
const config = (component as any).componentConfig || {};
const fieldName = (component as any).columnName || component.id;
// Unified 시스템이 있으면 거기서 값 가져오기, 없으면 props.formData 사용
const currentValue = unifiedFormContextForUnified
? unifiedFormContextForUnified.getValue(fieldName)
// V2 시스템이 있으면 거기서 값 가져오기, 없으면 props.formData 사용
const currentValue = v2FormContextLocal
? v2FormContextLocal.getValue(fieldName)
: props.formData?.[fieldName];
// 🆕 통합 onChange 핸들러 - 양쪽 시스템에 전파
const handleChange = (value: any) => {
// 1. Unified 시스템에 전파
if (unifiedFormContextForUnified) {
unifiedFormContextForUnified.setValue(fieldName, value);
// 1. V2 시스템에 전파
if (v2FormContextLocal) {
v2FormContextLocal.setValue(fieldName, value);
}
// 2. 레거시 콜백도 호출 (호환성)
if (props.onFormDataChange) {
@@ -252,15 +252,16 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
position: component.position,
};
switch (unifiedType) {
case "unified-input":
switch (v2Type) {
// V2 입력 컴포넌트
case "v2-input":
return (
<UnifiedInput
unifiedType="UnifiedInput"
<V2Input
v2Type="V2Input"
{...commonProps}
config={{
type: config.inputType || config.type || "text",
inputType: config.inputType || config.type || "text", // 🆕 inputType 명시적 전달
inputType: config.inputType || config.type || "text",
format: config.format,
placeholder: config.placeholder,
mask: config.mask,
@@ -270,7 +271,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
buttonText: config.buttonText,
buttonVariant: config.buttonVariant,
autoGeneration: config.autoGeneration,
tableName: (component as any).tableName || props.tableName, // 🆕 채번용 테이블명
tableName: (component as any).tableName || props.tableName,
}}
autoGeneration={config.autoGeneration}
formData={props.formData}
@@ -278,12 +279,12 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-select":
// 🆕 unified-select는 항상 테이블 컬럼에서 distinct 값을 자동 로드
// 정적 옵션(static)은 사용하지 않음
// V2 선택 컴포넌트
case "v2-select":
// v2-select는 항상 테이블 컬럼에서 distinct 값을 자동 로드
return (
<UnifiedSelect
unifiedType="UnifiedSelect"
<V2Select
v2Type="V2Select"
{...commonProps}
config={{
mode: config.mode || "dropdown",
@@ -305,10 +306,11 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-date":
// V2 날짜 컴포넌트
case "v2-date":
return (
<UnifiedDate
unifiedType="UnifiedDate"
<V2Date
v2Type="V2Date"
{...commonProps}
config={{
type: config.dateType || config.type || "date",
@@ -321,13 +323,13 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-list":
case "v2-list":
// 데이터 소스: config.data > props.tableDisplayData > []
const listData = config.data?.length > 0 ? config.data : props.tableDisplayData || [];
return (
<UnifiedList
unifiedType="UnifiedList"
<V2List
v2Type="V2List"
{...commonProps}
config={{
viewMode: config.viewMode || "table",
@@ -362,10 +364,10 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-layout":
case "v2-layout":
return (
<UnifiedLayout
unifiedType="UnifiedLayout"
<V2Layout
v2Type="V2Layout"
{...commonProps}
config={{
type: config.layoutType || config.type || "grid",
@@ -376,13 +378,13 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
}}
>
{children}
</UnifiedLayout>
</V2Layout>
);
case "unified-group":
case "v2-group":
return (
<UnifiedGroup
unifiedType="UnifiedGroup"
<V2Group
v2Type="V2Group"
{...commonProps}
config={{
type: config.groupType || config.type || "section",
@@ -394,13 +396,13 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
title={config.title}
>
{children}
</UnifiedGroup>
</V2Group>
);
case "unified-media":
case "v2-media":
return (
<UnifiedMedia
unifiedType="UnifiedMedia"
<V2Media
v2Type="V2Media"
{...commonProps}
config={{
type: config.mediaType || config.type || "image",
@@ -412,10 +414,10 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-biz":
case "v2-biz":
return (
<UnifiedBiz
unifiedType="UnifiedBiz"
<V2Biz
v2Type="V2Biz"
{...commonProps}
config={{
type: config.bizType || config.type || "flow",
@@ -426,10 +428,10 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-hierarchy":
case "v2-hierarchy":
return (
<UnifiedHierarchy
unifiedType="UnifiedHierarchy"
<V2Hierarchy
v2Type="V2Hierarchy"
{...commonProps}
config={{
type: config.hierarchyType || config.type || "tree",
@@ -441,14 +443,14 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
/>
);
case "unified-repeater":
case "v2-repeater":
// 🆕 저장 설정 추출 (useCustomTable, mainTableName, foreignKeyColumn)
const repeaterTargetTable = config.useCustomTable && config.mainTableName
? config.mainTableName
: config.dataSource?.tableName;
return (
<UnifiedRepeater
<V2Repeater
config={{
renderMode: config.renderMode || "inline",
// 🆕 저장 설정 추가
@@ -499,8 +501,8 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
return (
<div className="flex h-full w-full items-center justify-center rounded border-2 border-dashed border-amber-300 bg-amber-50 p-4">
<div className="text-center">
<div className="mb-2 text-sm font-medium text-amber-600">Unified </div>
<div className="text-xs text-amber-500"> : {unifiedType}</div>
<div className="mb-2 text-sm font-medium text-amber-600">V2 </div>
<div className="text-xs text-amber-500"> : {v2Type}</div>
</div>
</div>
);
@@ -653,12 +655,12 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
currentValue = formData?.[fieldName] || "";
}
// 🆕 Unified 폼 시스템 연동 (Context가 있으면 사용, 없으면 null)
// 🆕 V2 폼 시스템 연동 (Context가 있으면 사용, 없으면 null)
// eslint-disable-next-line react-hooks/rules-of-hooks
const unifiedFormContext = useUnifiedFormOptional();
const v2FormContext = useV2FormOptional();
// onChange 핸들러 - 컴포넌트 타입에 따라 다르게 처리
// 🆕 Unified 시스템과 레거시 시스템 모두에 전파
// 🆕 V2 시스템과 레거시 시스템 모두에 전파
const handleChange = (value: any) => {
// autocomplete-search-input, entity-search-input은 자체적으로 onFormDataChange를 호출하므로 중복 저장 방지
if (componentType === "autocomplete-search-input" || componentType === "entity-search-input") {
@@ -672,9 +674,9 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
actualValue = value.target.value;
}
// 1. Unified 폼 시스템에 전파 (있으면)
if (unifiedFormContext) {
unifiedFormContext.setValue(fieldName, actualValue);
// 1. V2 폼 시스템에 전파 (있으면)
if (v2FormContext) {
v2FormContext.setValue(fieldName, actualValue);
}
// 2. 레거시 onFormDataChange 콜백도 호출 (호환성 유지)