모달 잘 보이게 수정
This commit is contained in:
parent
1d6418ca63
commit
e2f4b47588
|
|
@ -364,7 +364,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
|||
</div>
|
||||
</ResizableDialogHeader>
|
||||
|
||||
<div className="flex flex-1 items-center justify-center overflow-auto">
|
||||
<div className="flex-1 overflow-auto p-6">
|
||||
{loading ? (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="text-center">
|
||||
|
|
@ -374,13 +374,11 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
|||
</div>
|
||||
) : screenData ? (
|
||||
<div
|
||||
className="relative bg-white"
|
||||
className="relative bg-white mx-auto"
|
||||
style={{
|
||||
width: screenDimensions?.width || 800,
|
||||
height: screenDimensions?.height || 600,
|
||||
width: `${screenDimensions?.width || 800}px`,
|
||||
height: `${screenDimensions?.height || 600}px`,
|
||||
transformOrigin: "center center",
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
}}
|
||||
>
|
||||
{screenData.components.map((component) => {
|
||||
|
|
|
|||
|
|
@ -401,15 +401,14 @@ export const InteractiveScreenViewer: React.FC<InteractiveScreenViewerProps> = (
|
|||
const applyStyles = (element: React.ReactElement) => {
|
||||
if (!comp.style) return element;
|
||||
|
||||
// ✅ 격자 시스템 잔재 제거: style.width, style.height는 무시
|
||||
// size.width, size.height가 부모 컨테이너에서 적용되므로
|
||||
const { width, height, ...styleWithoutSize } = comp.style;
|
||||
|
||||
return React.cloneElement(element, {
|
||||
style: {
|
||||
...element.props.style, // 기존 스타일 유지
|
||||
...comp.style,
|
||||
// 크기는 부모 컨테이너에서 처리하므로 제거 (하지만 다른 스타일은 유지)
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
minHeight: "100%",
|
||||
maxHeight: "100%",
|
||||
...styleWithoutSize, // width/height 제외한 스타일만 적용
|
||||
boxSizing: "border-box",
|
||||
},
|
||||
});
|
||||
|
|
@ -1887,7 +1886,7 @@ export const InteractiveScreenViewer: React.FC<InteractiveScreenViewerProps> = (
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="h-full w-full">
|
||||
<div className="h-full" style={{ width: '100%', height: '100%' }}>
|
||||
{/* 라벨이 있는 경우 표시 (데이터 테이블 제외) */}
|
||||
{shouldShowLabel && (
|
||||
<label className="mb-2 block text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
||||
|
|
@ -1897,7 +1896,7 @@ export const InteractiveScreenViewer: React.FC<InteractiveScreenViewerProps> = (
|
|||
)}
|
||||
|
||||
{/* 실제 위젯 - 상위에서 라벨을 렌더링했으므로 자식은 라벨 숨김 */}
|
||||
<div className="h-full w-full">{renderInteractiveWidget(componentForRendering)}</div>
|
||||
<div className="h-full" style={{ width: '100%', height: '100%' }}>{renderInteractiveWidget(componentForRendering)}</div>
|
||||
</div>
|
||||
|
||||
{/* 개선된 검증 패널 (선택적 표시) */}
|
||||
|
|
|
|||
|
|
@ -343,10 +343,14 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
|||
const applyStyles = (element: React.ReactElement) => {
|
||||
if (!comp.style) return element;
|
||||
|
||||
// ✅ 격자 시스템 잔재 제거: style.width, style.height는 무시
|
||||
// size.width, size.height가 부모 컨테이너에서 적용되므로
|
||||
const { width, height, ...styleWithoutSize } = comp.style;
|
||||
|
||||
return React.cloneElement(element, {
|
||||
style: {
|
||||
...element.props.style,
|
||||
...comp.style,
|
||||
...styleWithoutSize, // width/height 제외한 스타일만 적용
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
minHeight: "100%",
|
||||
|
|
@ -676,14 +680,17 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
|||
// 메인 렌더링
|
||||
const { type, position, size, style = {} } = component;
|
||||
|
||||
// ✅ 격자 시스템 잔재 제거: style.width, style.height 무시
|
||||
const { width: styleWidth, height: styleHeight, ...styleWithoutSize } = style;
|
||||
|
||||
const componentStyle = {
|
||||
position: "absolute" as const,
|
||||
left: position?.x || 0,
|
||||
top: position?.y || 0,
|
||||
width: size?.width || 200,
|
||||
height: size?.height || 10,
|
||||
zIndex: position?.z || 1,
|
||||
...style,
|
||||
...styleWithoutSize, // width/height 제외한 스타일만 먼저 적용
|
||||
width: size?.width || 200, // size의 픽셀 값이 최종 우선순위
|
||||
height: size?.height || 10,
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -200,8 +200,21 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
|||
const calculateDynamicSize = () => {
|
||||
if (!components.length) return { width: 800, height: 600 };
|
||||
|
||||
const maxX = Math.max(...components.map((c) => (c.position?.x || 0) + (c.size?.width || 200)));
|
||||
const maxY = Math.max(...components.map((c) => (c.position?.y || 0) + (c.size?.height || 40)));
|
||||
const maxX = Math.max(...components.map((c) => {
|
||||
const x = c.position?.x || 0;
|
||||
const width = typeof c.size?.width === 'number'
|
||||
? c.size.width
|
||||
: parseInt(String(c.size?.width || 200), 10);
|
||||
return x + width;
|
||||
}));
|
||||
|
||||
const maxY = Math.max(...components.map((c) => {
|
||||
const y = c.position?.y || 0;
|
||||
const height = typeof c.size?.height === 'number'
|
||||
? c.size.height
|
||||
: parseInt(String(c.size?.height || 40), 10);
|
||||
return y + height;
|
||||
}));
|
||||
|
||||
const padding = 40;
|
||||
return {
|
||||
|
|
@ -214,8 +227,15 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
|||
|
||||
return (
|
||||
<ResizableDialog open={isOpen} onOpenChange={(open) => !isSaving && !open && onClose()}>
|
||||
<ResizableDialogContent className={`${modalSizeClasses[modalSize]} max-h-[90vh] gap-0 p-0`}>
|
||||
<ResizableDialogHeader className="border-b px-6 py-4">
|
||||
<ResizableDialogContent
|
||||
modalId={`save-modal-${screenId}`}
|
||||
defaultWidth={dynamicSize.width + 48}
|
||||
defaultHeight={dynamicSize.height + 120}
|
||||
minWidth={400}
|
||||
minHeight={300}
|
||||
className="gap-0 p-0"
|
||||
>
|
||||
<ResizableDialogHeader className="border-b px-6 py-4 flex-shrink-0">
|
||||
<div className="flex items-center justify-between">
|
||||
<ResizableDialogTitle className="text-lg font-semibold">{initialData ? "데이터 수정" : "데이터 등록"}</ResizableDialogTitle>
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -239,29 +259,51 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
|||
</div>
|
||||
</ResizableDialogHeader>
|
||||
|
||||
<div className="overflow-auto p-6">
|
||||
<div className="overflow-auto p-6 flex-1">
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<Loader2 className="text-muted-foreground h-8 w-8 animate-spin" />
|
||||
</div>
|
||||
) : screenData && components.length > 0 ? (
|
||||
<div
|
||||
className="relative bg-white w-full h-full"
|
||||
className="relative bg-white"
|
||||
style={{
|
||||
minWidth: dynamicSize.width,
|
||||
minHeight: dynamicSize.height,
|
||||
width: `${dynamicSize.width}px`,
|
||||
height: `${dynamicSize.height}px`,
|
||||
minWidth: `${dynamicSize.width}px`,
|
||||
minHeight: `${dynamicSize.height}px`,
|
||||
}}
|
||||
>
|
||||
<div className="relative w-full h-full" style={{ minHeight: "300px" }}>
|
||||
{components.map((component, index) => (
|
||||
<div className="relative" style={{ width: `${dynamicSize.width}px`, height: `${dynamicSize.height}px` }}>
|
||||
{components.map((component, index) => {
|
||||
// ✅ 격자 시스템 잔재 제거: size의 픽셀 값만 사용
|
||||
const widthPx = typeof component.size?.width === 'number'
|
||||
? component.size.width
|
||||
: parseInt(String(component.size?.width || 200), 10);
|
||||
const heightPx = typeof component.size?.height === 'number'
|
||||
? component.size.height
|
||||
: parseInt(String(component.size?.height || 40), 10);
|
||||
|
||||
// 디버깅: 실제 크기 확인
|
||||
if (index === 0) {
|
||||
console.log('🔍 SaveModal 컴포넌트 크기:', {
|
||||
componentId: component.id,
|
||||
'size.width (원본)': component.size?.width,
|
||||
'size.width 타입': typeof component.size?.width,
|
||||
'widthPx (계산)': widthPx,
|
||||
'style.width': component.style?.width,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={component.id}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: component.position?.y || 0,
|
||||
left: component.position?.x || 0,
|
||||
width: component.size?.width || 200,
|
||||
height: component.size?.height || 40,
|
||||
width: `${widthPx}px`, // ✅ 픽셀 단위 강제
|
||||
height: `${heightPx}px`, // ✅ 픽셀 단위 강제
|
||||
zIndex: component.position?.z || 1000 + index,
|
||||
}}
|
||||
>
|
||||
|
|
@ -306,7 +348,8 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ interface ResizableDialogContentProps
|
|||
modalId?: string; // localStorage 저장용 고유 ID
|
||||
userId?: string; // 사용자별 저장용
|
||||
open?: boolean; // 🆕 모달 열림/닫힘 상태 (외부에서 전달)
|
||||
disableFlexLayout?: boolean; // 🆕 flex 레이아웃 비활성화 (absolute 레이아웃용)
|
||||
}
|
||||
|
||||
const ResizableDialogContent = React.forwardRef<
|
||||
|
|
@ -74,6 +75,7 @@ const ResizableDialogContent = React.forwardRef<
|
|||
modalId,
|
||||
userId = "guest",
|
||||
open: externalOpen, // 🆕 외부에서 전달받은 open 상태
|
||||
disableFlexLayout = false, // 🆕 flex 레이아웃 비활성화
|
||||
style: userStyle,
|
||||
...props
|
||||
},
|
||||
|
|
@ -373,7 +375,11 @@ const ResizableDialogContent = React.forwardRef<
|
|||
minHeight: `${minHeight}px`,
|
||||
}}
|
||||
>
|
||||
<div ref={contentRef} className="flex flex-col h-full overflow-auto">
|
||||
<div
|
||||
ref={contentRef}
|
||||
className="h-full w-full"
|
||||
style={{ display: 'block', overflow: 'hidden' }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue