Merge branch 'main' of http://39.117.244.52:3000/kjs/ERP-node into feat/dashboard
This commit is contained in:
@@ -200,19 +200,58 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||
: {};
|
||||
|
||||
// 컴포넌트 기본 스타일 - 레이아웃은 항상 맨 아래
|
||||
// 너비 우선순위: style.width > size.width (픽셀값)
|
||||
// 너비 우선순위: style.width > 조건부 100% > size.width (픽셀값)
|
||||
const getWidth = () => {
|
||||
// 1순위: style.width가 있으면 우선 사용
|
||||
// 1순위: style.width가 있으면 우선 사용 (퍼센트 값)
|
||||
if (componentStyle?.width) {
|
||||
console.log("✅ [getWidth] style.width 사용:", {
|
||||
componentId: id,
|
||||
label: component.label,
|
||||
styleWidth: componentStyle.width,
|
||||
gridColumns: (component as any).gridColumns,
|
||||
componentStyle: componentStyle,
|
||||
baseStyle: {
|
||||
left: `${position.x}px`,
|
||||
top: `${position.y}px`,
|
||||
width: componentStyle.width,
|
||||
height: getHeight(),
|
||||
},
|
||||
});
|
||||
return componentStyle.width;
|
||||
}
|
||||
|
||||
// 2순위: size.width (픽셀)
|
||||
if (component.componentConfig?.type === "table-list") {
|
||||
return `${Math.max(size?.width || 120, 120)}px`;
|
||||
// 2순위: x=0인 컴포넌트는 전체 너비 사용 (버튼 제외)
|
||||
const isButtonComponent =
|
||||
(component.type === "widget" && (component as WidgetComponent).widgetType === "button") ||
|
||||
(component.type === "component" && (component as any).componentType?.includes("button"));
|
||||
|
||||
if (position.x === 0 && !isButtonComponent) {
|
||||
console.log("⚠️ [getWidth] 100% 사용 (x=0):", {
|
||||
componentId: id,
|
||||
label: component.label,
|
||||
});
|
||||
return "100%";
|
||||
}
|
||||
|
||||
return `${size?.width || 100}px`;
|
||||
// 3순위: size.width (픽셀)
|
||||
if (component.componentConfig?.type === "table-list") {
|
||||
const width = `${Math.max(size?.width || 120, 120)}px`;
|
||||
console.log("📏 [getWidth] 픽셀 사용 (table-list):", {
|
||||
componentId: id,
|
||||
label: component.label,
|
||||
width,
|
||||
});
|
||||
return width;
|
||||
}
|
||||
|
||||
const width = `${size?.width || 100}px`;
|
||||
console.log("📏 [getWidth] 픽셀 사용 (기본):", {
|
||||
componentId: id,
|
||||
label: component.label,
|
||||
width,
|
||||
sizeWidth: size?.width,
|
||||
});
|
||||
return width;
|
||||
};
|
||||
|
||||
const getHeight = () => {
|
||||
@@ -247,17 +286,51 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||
const baseStyle = {
|
||||
left: `${position.x}px`,
|
||||
top: `${position.y}px`,
|
||||
// 🆕 left가 0이면 부모 너비를 100% 채우도록 수정 (우측 여백 제거)
|
||||
width: position.x === 0 ? "100%" : getWidth(),
|
||||
height: getHeight(), // 모든 컴포넌트 고정 높이로 변경
|
||||
zIndex: component.type === "layout" ? 1 : position.z || 2, // 레이아웃은 z-index 1, 다른 컴포넌트는 2 이상
|
||||
width: getWidth(), // getWidth()가 모든 우선순위를 처리
|
||||
height: getHeight(),
|
||||
zIndex: component.type === "layout" ? 1 : position.z || 2,
|
||||
...componentStyle,
|
||||
// style.width가 있어도 position.x === 0이면 100%로 강제
|
||||
...(position.x === 0 && { width: "100%" }),
|
||||
// right 속성 강제 제거
|
||||
right: undefined,
|
||||
};
|
||||
|
||||
// 🔍 DOM 렌더링 후 실제 크기 측정
|
||||
const innerDivRef = React.useRef<HTMLDivElement>(null);
|
||||
const outerDivRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (outerDivRef.current && innerDivRef.current) {
|
||||
const outerRect = outerDivRef.current.getBoundingClientRect();
|
||||
const innerRect = innerDivRef.current.getBoundingClientRect();
|
||||
const computedOuter = window.getComputedStyle(outerDivRef.current);
|
||||
const computedInner = window.getComputedStyle(innerDivRef.current);
|
||||
|
||||
console.log("📐 [DOM 실제 크기 상세]:", {
|
||||
componentId: id,
|
||||
label: component.label,
|
||||
gridColumns: (component as any).gridColumns,
|
||||
"1. baseStyle.width": baseStyle.width,
|
||||
"2. 외부 div (파란 테두리)": {
|
||||
width: `${outerRect.width}px`,
|
||||
height: `${outerRect.height}px`,
|
||||
computedWidth: computedOuter.width,
|
||||
computedHeight: computedOuter.height,
|
||||
},
|
||||
"3. 내부 div (컨텐츠 래퍼)": {
|
||||
width: `${innerRect.width}px`,
|
||||
height: `${innerRect.height}px`,
|
||||
computedWidth: computedInner.width,
|
||||
computedHeight: computedInner.height,
|
||||
className: innerDivRef.current.className,
|
||||
inlineStyle: innerDivRef.current.getAttribute("style"),
|
||||
},
|
||||
"4. 너비 비교": {
|
||||
"외부 / 내부": `${outerRect.width}px / ${innerRect.width}px`,
|
||||
"비율": `${((innerRect.width / outerRect.width) * 100).toFixed(2)}%`,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [id, component.label, (component as any).gridColumns, baseStyle.width]);
|
||||
|
||||
const handleClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onClick?.(e);
|
||||
@@ -279,7 +352,9 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={outerDivRef}
|
||||
id={`component-${id}`}
|
||||
data-component-id={id}
|
||||
className="absolute cursor-pointer transition-all duration-200 ease-out"
|
||||
style={{ ...baseStyle, ...selectionStyle }}
|
||||
onClick={handleClick}
|
||||
@@ -290,10 +365,15 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
|
||||
>
|
||||
{/* 동적 컴포넌트 렌더링 */}
|
||||
<div
|
||||
ref={
|
||||
component.type === "component" && (component as any).componentType === "flow-widget" ? contentRef : undefined
|
||||
}
|
||||
className={`${component.type === "component" && (component as any).componentType === "flow-widget" ? "h-auto" : "h-full"} w-full max-w-full overflow-visible`}
|
||||
ref={(node) => {
|
||||
// 멀티 ref 처리
|
||||
innerDivRef.current = node;
|
||||
if (component.type === "component" && (component as any).componentType === "flow-widget") {
|
||||
(contentRef as any).current = node;
|
||||
}
|
||||
}}
|
||||
className={`${component.type === "component" && (component as any).componentType === "flow-widget" ? "h-auto" : "h-full"} overflow-visible`}
|
||||
style={{ width: "100%", maxWidth: "100%" }}
|
||||
>
|
||||
<DynamicComponentRenderer
|
||||
component={component}
|
||||
|
||||
Reference in New Issue
Block a user