Merge remote-tracking branch 'origin/main' into ksh
This commit is contained in:
commit
cee9903f94
|
|
@ -40,6 +40,7 @@ export const EmbeddedScreen = forwardRef<EmbeddedScreenHandle, EmbeddedScreenPro
|
|||
const [error, setError] = useState<string | null>(null);
|
||||
const [screenInfo, setScreenInfo] = useState<any>(null);
|
||||
const [formData, setFormData] = useState<Record<string, any>>(initialFormData || {}); // 🆕 초기 데이터로 시작
|
||||
const [formDataVersion, setFormDataVersion] = useState(0); // 🆕 폼 데이터 버전 (강제 리렌더링용)
|
||||
|
||||
// 컴포넌트 참조 맵
|
||||
const componentRefs = useRef<Map<string, DataReceivable>>(new Map());
|
||||
|
|
@ -92,26 +93,49 @@ export const EmbeddedScreen = forwardRef<EmbeddedScreenHandle, EmbeddedScreenPro
|
|||
}, [initialFormData]);
|
||||
|
||||
// 🆕 분할 패널에서 좌측 선택 데이터가 변경되면 우측 화면의 formData에 자동 반영
|
||||
// disableAutoDataTransfer가 true이면 자동 전달 비활성화 (버튼 클릭으로만 전달)
|
||||
// 🆕 좌측 선택 데이터 (분할 패널 컨텍스트에서 직접 참조)
|
||||
const selectedLeftData = splitPanelContext?.selectedLeftData;
|
||||
|
||||
// 🆕 좌측 선택 데이터가 변경되면 우측 formData를 업데이트
|
||||
useEffect(() => {
|
||||
// 우측 화면인 경우에만 적용
|
||||
if (position !== "right" || !splitPanelContext) return;
|
||||
|
||||
// 자동 데이터 전달이 비활성화된 경우 스킵
|
||||
if (splitPanelContext.disableAutoDataTransfer) {
|
||||
console.log("🔗 [EmbeddedScreen] 자동 데이터 전달 비활성화됨 - 버튼 클릭으로만 전달");
|
||||
if (position !== "right" || !splitPanelContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mappedData = splitPanelContext.getMappedParentData();
|
||||
if (Object.keys(mappedData).length > 0) {
|
||||
console.log("🔗 [EmbeddedScreen] 분할 패널 부모 데이터 자동 반영:", mappedData);
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
...mappedData,
|
||||
}));
|
||||
// 자동 데이터 전달이 비활성화된 경우 스킵
|
||||
if (splitPanelContext.disableAutoDataTransfer) {
|
||||
return;
|
||||
}
|
||||
}, [position, splitPanelContext, splitPanelContext?.selectedLeftData]);
|
||||
|
||||
// 🆕 현재 화면의 모든 컴포넌트에서 columnName 수집
|
||||
const allColumnNames = layout.filter((comp) => comp.columnName).map((comp) => comp.columnName as string);
|
||||
|
||||
// 🆕 모든 필드를 빈 값으로 초기화한 후, selectedLeftData로 덮어쓰기
|
||||
const initializedFormData: Record<string, any> = {};
|
||||
|
||||
// 먼저 모든 컬럼을 빈 문자열로 초기화
|
||||
allColumnNames.forEach((colName) => {
|
||||
initializedFormData[colName] = "";
|
||||
});
|
||||
|
||||
// selectedLeftData가 있으면 해당 값으로 덮어쓰기
|
||||
if (selectedLeftData && Object.keys(selectedLeftData).length > 0) {
|
||||
Object.keys(selectedLeftData).forEach((key) => {
|
||||
// null/undefined는 빈 문자열로, 나머지는 그대로
|
||||
initializedFormData[key] = selectedLeftData[key] ?? "";
|
||||
});
|
||||
}
|
||||
|
||||
console.log("🔗 [EmbeddedScreen] 우측 폼 데이터 교체:", {
|
||||
allColumnNames,
|
||||
selectedLeftDataKeys: selectedLeftData ? Object.keys(selectedLeftData) : [],
|
||||
initializedFormDataKeys: Object.keys(initializedFormData),
|
||||
});
|
||||
|
||||
setFormData(initializedFormData);
|
||||
setFormDataVersion((v) => v + 1); // 🆕 버전 증가로 컴포넌트 강제 리렌더링
|
||||
}, [position, splitPanelContext, selectedLeftData, layout]);
|
||||
|
||||
// 선택 변경 이벤트 전파
|
||||
useEffect(() => {
|
||||
|
|
@ -399,11 +423,7 @@ export const EmbeddedScreen = forwardRef<EmbeddedScreenHandle, EmbeddedScreenPro
|
|||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={component.id}
|
||||
className="absolute"
|
||||
style={componentStyle}
|
||||
>
|
||||
<div key={`${component.id}-${formDataVersion}`} className="absolute" style={componentStyle}>
|
||||
<DynamicComponentRenderer
|
||||
component={component}
|
||||
isInteractive={true}
|
||||
|
|
|
|||
|
|
@ -919,21 +919,27 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
// 🆕 분할 패널 우측이면 screenContext.formData와 props.formData를 병합
|
||||
// screenContext.formData: RepeaterFieldGroup 등 컴포넌트가 직접 업데이트한 데이터
|
||||
// props.formData: 부모에서 전달된 폼 데이터
|
||||
// 🆕 분할 패널 우측이면 여러 소스에서 formData를 병합
|
||||
// 우선순위: props.formData > screenContext.formData > splitPanelParentData
|
||||
const screenContextFormData = screenContext?.formData || {};
|
||||
const propsFormData = formData || {};
|
||||
|
||||
// 병합: props.formData를 기본으로 하고, screenContext.formData로 오버라이드
|
||||
// (RepeaterFieldGroup 데이터는 screenContext에만 있음)
|
||||
const effectiveFormData = { ...propsFormData, ...screenContextFormData };
|
||||
// 병합: splitPanelParentData를 기본으로, props.formData, screenContext.formData 순으로 오버라이드
|
||||
// (일반 폼 필드는 props.formData, RepeaterFieldGroup은 screenContext.formData에 있음)
|
||||
let effectiveFormData = { ...propsFormData, ...screenContextFormData };
|
||||
|
||||
// 🆕 분할 패널 우측이고 formData가 비어있으면 splitPanelParentData 사용
|
||||
if (splitPanelPosition === "right" && Object.keys(effectiveFormData).length === 0 && splitPanelParentData) {
|
||||
effectiveFormData = { ...splitPanelParentData };
|
||||
console.log("🔍 [ButtonPrimary] 분할 패널 우측 - splitPanelParentData 사용:", Object.keys(effectiveFormData));
|
||||
}
|
||||
|
||||
console.log("🔍 [ButtonPrimary] formData 선택:", {
|
||||
hasScreenContextFormData: Object.keys(screenContextFormData).length > 0,
|
||||
screenContextKeys: Object.keys(screenContextFormData),
|
||||
hasPropsFormData: Object.keys(propsFormData).length > 0,
|
||||
propsFormDataKeys: Object.keys(propsFormData),
|
||||
hasSplitPanelParentData: !!splitPanelParentData && Object.keys(splitPanelParentData).length > 0,
|
||||
splitPanelPosition,
|
||||
effectiveFormDataKeys: Object.keys(effectiveFormData),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
const currentFormValue = formData?.[component.columnName];
|
||||
const currentComponentValue = component.value;
|
||||
|
||||
|
||||
// 자동생성된 값이 없고, 현재 값도 없을 때만 생성
|
||||
if (!autoGeneratedValue && !currentFormValue && !currentComponentValue) {
|
||||
isGeneratingRef.current = true; // 생성 시작 플래그
|
||||
|
|
@ -181,12 +180,12 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
// width는 항상 100%로 고정 (부모 컨테이너가 gridColumns로 크기 제어)
|
||||
width: "100%",
|
||||
// 숨김 기능: 편집 모드에서만 연하게 표시
|
||||
...(isHidden &&
|
||||
isDesignMode && {
|
||||
opacity: 0.4,
|
||||
backgroundColor: "hsl(var(--muted))",
|
||||
pointerEvents: "auto",
|
||||
}),
|
||||
...(isHidden &&
|
||||
isDesignMode && {
|
||||
opacity: 0.4,
|
||||
backgroundColor: "hsl(var(--muted))",
|
||||
pointerEvents: "auto",
|
||||
}),
|
||||
};
|
||||
|
||||
// 디자인 모드 스타일
|
||||
|
|
@ -361,7 +360,7 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
<div className={`relative w-full ${className || ""}`} style={componentStyle} {...safeDomProps}>
|
||||
{/* 라벨 렌더링 */}
|
||||
{component.label && component.style?.labelDisplay !== false && (
|
||||
<label className="absolute -top-6 left-0 text-sm font-medium text-muted-foreground">
|
||||
<label className="text-muted-foreground absolute -top-6 left-0 text-sm font-medium">
|
||||
{component.label}
|
||||
{component.required && <span className="text-destructive">*</span>}
|
||||
</label>
|
||||
|
|
@ -386,15 +385,17 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* @ 구분자 */}
|
||||
<span className="text-base font-medium text-muted-foreground">@</span>
|
||||
<span className="text-muted-foreground text-base font-medium">@</span>
|
||||
|
||||
{/* 도메인 선택/입력 (Combobox) */}
|
||||
<Popover open={emailDomainOpen} onOpenChange={setEmailDomainOpen}>
|
||||
|
|
@ -406,14 +407,18 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
disabled={componentConfig.disabled || false}
|
||||
className={cn(
|
||||
"flex h-full flex-1 items-center justify-between rounded-md border px-3 py-2 text-sm transition-all duration-200",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "cursor-not-allowed bg-muted text-muted-foreground opacity-50" : "bg-background text-foreground",
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"hover:border-ring/80",
|
||||
emailDomainOpen && "border-ring ring-2 ring-ring/50",
|
||||
emailDomainOpen && "border-ring ring-ring/50 ring-2",
|
||||
)}
|
||||
>
|
||||
<span className={cn("truncate", !emailDomain && "text-muted-foreground")}>{emailDomain || "도메인 선택"}</span>
|
||||
<span className={cn("truncate", !emailDomain && "text-muted-foreground")}>
|
||||
{emailDomain || "도메인 선택"}
|
||||
</span>
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
|
|
@ -470,7 +475,7 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
<div className={`relative w-full ${className || ""}`} style={componentStyle} {...safeDomProps}>
|
||||
{/* 라벨 렌더링 */}
|
||||
{component.label && component.style?.labelDisplay !== false && (
|
||||
<label className="absolute -top-6 left-0 text-sm font-medium text-muted-foreground">
|
||||
<label className="text-muted-foreground absolute -top-6 left-0 text-sm font-medium">
|
||||
{component.label}
|
||||
{component.required && <span className="text-destructive">*</span>}
|
||||
</label>
|
||||
|
|
@ -496,14 +501,16 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
/>
|
||||
|
||||
<span className="text-base font-medium text-muted-foreground">-</span>
|
||||
<span className="text-muted-foreground text-base font-medium">-</span>
|
||||
|
||||
{/* 두 번째 부분 */}
|
||||
<input
|
||||
|
|
@ -524,14 +531,16 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
/>
|
||||
|
||||
<span className="text-base font-medium text-muted-foreground">-</span>
|
||||
<span className="text-muted-foreground text-base font-medium">-</span>
|
||||
|
||||
{/* 세 번째 부분 */}
|
||||
<input
|
||||
|
|
@ -552,10 +561,12 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"h-full flex-1 rounded-md border px-3 py-2 text-center text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -569,7 +580,7 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
<div className={`relative w-full ${className || ""}`} style={componentStyle} {...safeDomProps}>
|
||||
{/* 라벨 렌더링 */}
|
||||
{component.label && component.style?.labelDisplay !== false && (
|
||||
<label className="absolute -top-6 left-0 text-sm font-medium text-muted-foreground">
|
||||
<label className="text-muted-foreground absolute -top-6 left-0 text-sm font-medium">
|
||||
{component.label}
|
||||
{component.required && <span className="text-destructive">*</span>}
|
||||
</label>
|
||||
|
|
@ -591,10 +602,12 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"h-full w-[100px] cursor-pointer rounded-md border px-2 py-2 text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
>
|
||||
<option value="https://">https://</option>
|
||||
|
|
@ -619,10 +632,12 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -636,7 +651,7 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
<div className={`relative w-full ${className || ""}`} style={componentStyle} {...safeDomProps}>
|
||||
{/* 라벨 렌더링 */}
|
||||
{component.label && component.style?.labelDisplay !== false && (
|
||||
<label className="absolute -top-6 left-0 text-sm font-medium text-muted-foreground">
|
||||
<label className="text-muted-foreground absolute -top-6 left-0 text-sm font-medium">
|
||||
{component.label}
|
||||
{component.required && <span className="text-destructive">*</span>}
|
||||
</label>
|
||||
|
|
@ -669,11 +684,13 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
}}
|
||||
className={cn(
|
||||
"box-border h-full w-full max-w-full resize-none rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
"placeholder:text-muted-foreground",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -692,13 +709,15 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
|
||||
{/* 수동/자동 모드 표시 배지 */}
|
||||
{testAutoGeneration.enabled && testAutoGeneration.type === "numbering_rule" && isInteractive && (
|
||||
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1">
|
||||
<span className={cn(
|
||||
"text-[10px] px-2 py-0.5 rounded-full font-medium",
|
||||
isManualMode
|
||||
? "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400"
|
||||
: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"
|
||||
)}>
|
||||
<div className="absolute top-1/2 right-2 flex -translate-y-1/2 items-center gap-1">
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-full px-2 py-0.5 text-[10px] font-medium",
|
||||
isManualMode
|
||||
? "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400"
|
||||
: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
||||
)}
|
||||
>
|
||||
{isManualMode ? "수동" : "자동"}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -706,12 +725,12 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
|
||||
<input
|
||||
type={inputType}
|
||||
defaultValue={(() => {
|
||||
value={(() => {
|
||||
let displayValue = "";
|
||||
|
||||
if (isInteractive && formData && component.columnName) {
|
||||
// 인터랙티브 모드: formData 우선, 없으면 자동생성 값
|
||||
const rawValue = formData[component.columnName] || autoGeneratedValue || "";
|
||||
const rawValue = formData[component.columnName] ?? autoGeneratedValue ?? "";
|
||||
// 객체인 경우 빈 문자열로 변환 (에러 방지)
|
||||
displayValue = typeof rawValue === "object" ? "" : String(rawValue);
|
||||
} else {
|
||||
|
|
@ -735,20 +754,22 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
? "전화번호 형식: 010-1234-5678"
|
||||
: isManualMode
|
||||
? `${component.label} (수동 입력 모드 - 채번 규칙 미적용)`
|
||||
: component.label
|
||||
? `${component.label}${component.columnName ? ` (${component.columnName})` : ""}`
|
||||
: component.columnName || undefined
|
||||
: component.label
|
||||
? `${component.label}${component.columnName ? ` (${component.columnName})` : ""}`
|
||||
: component.columnName || undefined
|
||||
}
|
||||
disabled={componentConfig.disabled || false}
|
||||
required={componentConfig.required || false}
|
||||
readOnly={componentConfig.readonly || false}
|
||||
className={cn(
|
||||
"box-border h-full w-full max-w-full rounded-md border px-3 py-2 text-sm shadow-sm transition-all duration-200 outline-none",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
||||
"placeholder:text-muted-foreground",
|
||||
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
|
||||
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed"
|
||||
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
|
||||
componentConfig.disabled
|
||||
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
|
||||
: "bg-background text-foreground",
|
||||
"disabled:cursor-not-allowed",
|
||||
)}
|
||||
onClick={(e) => {
|
||||
handleClick(e);
|
||||
|
|
@ -774,7 +795,7 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
console.log("🔄 수동 모드로 전환:", {
|
||||
field: component.columnName,
|
||||
original: originalAutoGeneratedValue,
|
||||
modified: newValue
|
||||
modified: newValue,
|
||||
});
|
||||
|
||||
// 🆕 채번 규칙 ID 제거 (수동 모드이므로 더 이상 채번 규칙 사용 안 함)
|
||||
|
|
@ -789,7 +810,7 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
setIsManualMode(false);
|
||||
console.log("🔄 자동 모드로 복구:", {
|
||||
field: component.columnName,
|
||||
value: newValue
|
||||
value: newValue,
|
||||
});
|
||||
|
||||
// 채번 규칙 ID 복구
|
||||
|
|
|
|||
Loading…
Reference in New Issue