f.objid) || [])}-${componentFiles.length}`;
@@ -3556,16 +3575,16 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
// 설정 변경 핸들러 (테이블 페이지 크기 등 설정을 상세설정에 반영)
onConfigChange={(config) => {
// console.log("📤 테이블 설정 변경을 상세설정에 반영:", config);
-
+
// 컴포넌트의 componentConfig 업데이트
- const updatedComponents = layout.components.map(comp => {
+ const updatedComponents = layout.components.map((comp) => {
if (comp.id === component.id) {
return {
...comp,
componentConfig: {
...comp.componentConfig,
- ...config
- }
+ ...config,
+ },
};
}
return comp;
@@ -3573,15 +3592,15 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
const newLayout = {
...layout,
- components: updatedComponents
+ components: updatedComponents,
};
setLayout(newLayout);
saveToHistory(newLayout);
-
+
console.log("✅ 컴포넌트 설정 업데이트 완료:", {
componentId: component.id,
- updatedConfig: config
+ updatedConfig: config,
});
}}
>
@@ -3858,36 +3877,25 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
{
- console.log("🔧 StyleEditor 크기 변경:", {
+ console.log("🔧 StyleEditor 스타일 변경:", {
componentId: selectedComponent.id,
newStyle,
- currentSize: selectedComponent.size,
- hasWidth: !!newStyle.width,
hasHeight: !!newStyle.height,
});
// 스타일 업데이트
updateComponentProperty(selectedComponent.id, "style", newStyle);
- // 크기가 변경된 경우 component.size도 업데이트
- if (newStyle.width || newStyle.height) {
- const width = newStyle.width
- ? parseInt(newStyle.width.replace("px", ""))
- : selectedComponent.size.width;
- const height = newStyle.height
- ? parseInt(newStyle.height.replace("px", ""))
- : selectedComponent.size.height;
+ // ✅ 높이만 업데이트 (너비는 gridColumnSpan으로 제어)
+ if (newStyle.height) {
+ const height = parseInt(newStyle.height.replace("px", ""));
- console.log("📏 크기 업데이트:", {
- originalWidth: selectedComponent.size.width,
+ console.log("📏 높이 업데이트:", {
originalHeight: selectedComponent.size.height,
- newWidth: width,
newHeight: height,
- styleWidth: newStyle.width,
styleHeight: newStyle.height,
});
- updateComponentProperty(selectedComponent.id, "size.width", width);
updateComponentProperty(selectedComponent.id, "size.height", height);
}
}}
diff --git a/frontend/components/screen/layout/ContainerComponent.tsx b/frontend/components/screen/layout/ContainerComponent.tsx
index c2cc4453..4001f284 100644
--- a/frontend/components/screen/layout/ContainerComponent.tsx
+++ b/frontend/components/screen/layout/ContainerComponent.tsx
@@ -2,6 +2,7 @@
import { cn } from "@/lib/utils";
import { ContainerComponent as ContainerComponentType } from "@/types/screen";
+import { buildGridClasses, COLUMN_SPAN_VALUES } from "@/lib/constants/columnSpans";
interface ContainerComponentProps {
component: ContainerComponentType;
@@ -22,12 +23,20 @@ export default function ContainerComponent({
onMouseDown,
isMoving,
}: ContainerComponentProps) {
+ // 그리드 클래스 생성
+ const gridClasses = component.gridColumnSpan
+ ? buildGridClasses(component.gridColumnSpan, component.gridColumnStart)
+ : "";
+
// 스타일 객체 생성
const style: React.CSSProperties = {
- gridColumn: `span ${component.size.width}`,
+ // 🔄 레거시 호환: gridColumnSpan이 없으면 기존 width 사용
+ ...(!component.gridColumnSpan && {
+ gridColumn: `span ${component.size.width}`,
+ }),
minHeight: `${component.size.height}px`,
...(component.style && {
- width: component.style.width,
+ // ❌ width는 제거 (그리드 클래스로 제어)
height: component.style.height,
margin: component.style.margin,
padding: component.style.padding,
@@ -63,6 +72,7 @@ export default function ContainerComponent({
= ({
}) => {
// 🔍 디버깅: PropertiesPanel 렌더링 및 dragState 전달 확인
// console.log("📍 PropertiesPanel 렌더링:", {
- // renderTime: Date.now(),
- // selectedComponentId: selectedComponent?.id,
- // dragState: dragState
- // ? {
- // isDragging: dragState.isDragging,
- // draggedComponentId: dragState.draggedComponent?.id,
- // currentPosition: dragState.currentPosition,
- // dragStateRef: dragState, // 객체 참조 확인
- // }
- // : "null",
+ // renderTime: Date.now(),
+ // selectedComponentId: selectedComponent?.id,
+ // dragState: dragState
+ // ? {
+ // isDragging: dragState.isDragging,
+ // draggedComponentId: dragState.draggedComponent?.id,
+ // currentPosition: dragState.currentPosition,
+ // dragStateRef: dragState, // 객체 참조 확인
+ // }
+ // : "null",
// });
// 동적 웹타입 목록 가져오기 - API에서 직접 조회
@@ -161,9 +165,9 @@ const PropertiesPanelComponent: React.FC
= ({
const getCurrentPosition = () => {
if (dragState?.isDragging && dragState.draggedComponent?.id === selectedComponent?.id) {
// console.log("🎯 드래그 중 실시간 위치:", {
- // draggedId: dragState.draggedComponent?.id,
- // selectedId: selectedComponent?.id,
- // currentPosition: dragState.currentPosition,
+ // draggedId: dragState.draggedComponent?.id,
+ // selectedId: selectedComponent?.id,
+ // currentPosition: dragState.currentPosition,
// });
return {
x: Math.round(dragState.currentPosition.x),
@@ -226,20 +230,20 @@ const PropertiesPanelComponent: React.FC = ({
const area = selectedComponent.type === "area" ? (selectedComponent as AreaComponent) : null;
// console.log("🔄 PropertiesPanel: 컴포넌트 변경 감지", {
- // componentId: selectedComponent.id,
- // componentType: selectedComponent.type,
- // isDragging: dragState?.isDragging,
- // justFinishedDrag: dragState?.justFinishedDrag,
- // currentValues: {
- // placeholder: widget?.placeholder,
- // title: group?.title || area?.title,
- // description: area?.description,
- // actualPositionX: selectedComponent.position.x,
- // actualPositionY: selectedComponent.position.y,
- // dragPositionX: dragState?.currentPosition.x,
- // dragPositionY: dragState?.currentPosition.y,
- // },
- // getCurrentPosResult: getCurrentPosition(),
+ // componentId: selectedComponent.id,
+ // componentType: selectedComponent.type,
+ // isDragging: dragState?.isDragging,
+ // justFinishedDrag: dragState?.justFinishedDrag,
+ // currentValues: {
+ // placeholder: widget?.placeholder,
+ // title: group?.title || area?.title,
+ // description: area?.description,
+ // actualPositionX: selectedComponent.position.x,
+ // actualPositionY: selectedComponent.position.y,
+ // dragPositionX: dragState?.currentPosition.x,
+ // dragPositionY: dragState?.currentPosition.y,
+ // },
+ // getCurrentPosResult: getCurrentPosition(),
// });
// 드래그 중이 아닐 때만 localInputs 업데이트 (드래그 완료 후 최종 위치 반영)
@@ -271,8 +275,8 @@ const PropertiesPanelComponent: React.FC = ({
});
// console.log("✅ localInputs 업데이트 완료:", {
- // positionX: currentPos.x.toString(),
- // positionY: currentPos.y.toString(),
+ // positionX: currentPos.x.toString(),
+ // positionY: currentPos.y.toString(),
// });
}
}
@@ -290,65 +294,66 @@ const PropertiesPanelComponent: React.FC = ({
if (selectedComponent && selectedComponent.type === "component") {
// 삭제 액션 감지 로직 (실제 필드명 사용)
const isDeleteAction = () => {
- const deleteKeywords = ['삭제', 'delete', 'remove', '제거', 'del'];
+ const deleteKeywords = ["삭제", "delete", "remove", "제거", "del"];
return (
- selectedComponent.componentConfig?.action?.type === 'delete' ||
- selectedComponent.config?.action?.type === 'delete' ||
- selectedComponent.webTypeConfig?.actionType === 'delete' ||
- selectedComponent.text?.toLowerCase().includes('삭제') ||
- selectedComponent.text?.toLowerCase().includes('delete') ||
- selectedComponent.label?.toLowerCase().includes('삭제') ||
- selectedComponent.label?.toLowerCase().includes('delete') ||
- deleteKeywords.some(keyword =>
- selectedComponent.config?.buttonText?.toLowerCase().includes(keyword) ||
- selectedComponent.config?.text?.toLowerCase().includes(keyword)
+ selectedComponent.componentConfig?.action?.type === "delete" ||
+ selectedComponent.config?.action?.type === "delete" ||
+ selectedComponent.webTypeConfig?.actionType === "delete" ||
+ selectedComponent.text?.toLowerCase().includes("삭제") ||
+ selectedComponent.text?.toLowerCase().includes("delete") ||
+ selectedComponent.label?.toLowerCase().includes("삭제") ||
+ selectedComponent.label?.toLowerCase().includes("delete") ||
+ deleteKeywords.some(
+ (keyword) =>
+ selectedComponent.config?.buttonText?.toLowerCase().includes(keyword) ||
+ selectedComponent.config?.text?.toLowerCase().includes(keyword),
)
);
};
// 🔍 디버깅: 컴포넌트 구조 확인
// console.log("🔍 PropertiesPanel 삭제 액션 디버깅:", {
- // componentType: selectedComponent.type,
- // componentId: selectedComponent.id,
- // componentConfig: selectedComponent.componentConfig,
- // config: selectedComponent.config,
- // webTypeConfig: selectedComponent.webTypeConfig,
- // actionType1: selectedComponent.componentConfig?.action?.type,
- // actionType2: selectedComponent.config?.action?.type,
- // actionType3: selectedComponent.webTypeConfig?.actionType,
- // isDeleteAction: isDeleteAction(),
- // currentLabelColor: selectedComponent.style?.labelColor,
+ // componentType: selectedComponent.type,
+ // componentId: selectedComponent.id,
+ // componentConfig: selectedComponent.componentConfig,
+ // config: selectedComponent.config,
+ // webTypeConfig: selectedComponent.webTypeConfig,
+ // actionType1: selectedComponent.componentConfig?.action?.type,
+ // actionType2: selectedComponent.config?.action?.type,
+ // actionType3: selectedComponent.webTypeConfig?.actionType,
+ // isDeleteAction: isDeleteAction(),
+ // currentLabelColor: selectedComponent.style?.labelColor,
// });
// 액션에 따른 라벨 색상 자동 설정
if (isDeleteAction()) {
// 삭제 액션일 때 빨간색으로 설정 (이미 빨간색이 아닌 경우에만)
- if (selectedComponent.style?.labelColor !== '#ef4444') {
+ if (selectedComponent.style?.labelColor !== "#ef4444") {
// console.log("🔴 삭제 액션 감지: 라벨 색상을 빨간색으로 자동 설정");
onUpdateProperty("style", {
...selectedComponent.style,
- labelColor: '#ef4444'
+ labelColor: "#ef4444",
});
-
+
// 로컬 입력 상태도 업데이트
- setLocalInputs(prev => ({
+ setLocalInputs((prev) => ({
...prev,
- labelColor: '#ef4444'
+ labelColor: "#ef4444",
}));
}
} else {
// 다른 액션일 때 기본 파란색으로 리셋 (현재 빨간색인 경우에만)
- if (selectedComponent.style?.labelColor === '#ef4444') {
+ if (selectedComponent.style?.labelColor === "#ef4444") {
// console.log("🔵 일반 액션 감지: 라벨 색상을 기본 파란색으로 리셋");
onUpdateProperty("style", {
...selectedComponent.style,
- labelColor: '#212121'
+ labelColor: "#212121",
});
-
+
// 로컬 입력 상태도 업데이트
- setLocalInputs(prev => ({
+ setLocalInputs((prev) => ({
...prev,
- labelColor: '#212121'
+ labelColor: "#212121",
}));
}
}
@@ -360,16 +365,16 @@ const PropertiesPanelComponent: React.FC = ({
selectedComponent?.id,
selectedComponent?.style?.labelColor, // 라벨 색상 변경도 감지
JSON.stringify(selectedComponent?.componentConfig), // 전체 componentConfig 변경 감지
- onUpdateProperty
+ onUpdateProperty,
]);
// 렌더링 시마다 실행되는 직접적인 드래그 상태 체크
if (dragState?.isDragging && dragState.draggedComponent?.id === selectedComponent?.id) {
// console.log("🎯 렌더링 중 드래그 상태 감지:", {
- // isDragging: dragState.isDragging,
- // draggedId: dragState.draggedComponent?.id,
- // selectedId: selectedComponent?.id,
- // currentPosition: dragState.currentPosition,
+ // isDragging: dragState.isDragging,
+ // draggedId: dragState.draggedComponent?.id,
+ // selectedId: selectedComponent?.id,
+ // currentPosition: dragState.currentPosition,
// });
const newPosition = {
@@ -380,8 +385,8 @@ const PropertiesPanelComponent: React.FC = ({
// 위치가 변경되었는지 확인
if (lastDragPosition.x !== newPosition.x || lastDragPosition.y !== newPosition.y) {
// console.log("🔄 위치 변경 감지됨:", {
- // oldPosition: lastDragPosition,
- // newPosition: newPosition,
+ // oldPosition: lastDragPosition,
+ // newPosition: newPosition,
// });
// 다음 렌더링 사이클에서 업데이트
setTimeout(() => {
@@ -409,7 +414,7 @@ const PropertiesPanelComponent: React.FC = ({
-
+
데이터 테이블 설정
@@ -450,7 +455,7 @@ const PropertiesPanelComponent: React.FC = ({
-
+
속성 편집
@@ -491,7 +496,7 @@ const PropertiesPanelComponent: React.FC = ({
{/* 기본 정보 */}
-
+
기본 정보
@@ -507,7 +512,7 @@ const PropertiesPanelComponent: React.FC
= ({
value={selectedComponent.columnName || ""}
readOnly
placeholder="데이터베이스 컬럼명"
- className="mt-1 bg-gray-50 text-muted-foreground"
+ className="text-muted-foreground mt-1 bg-gray-50"
title="컬럼명은 변경할 수 없습니다"
/>
@@ -517,7 +522,7 @@ const PropertiesPanelComponent: React.FC = ({
위젯 타입