next.js 버전 15.4.8

This commit is contained in:
kjs 2025-12-04 10:39:07 +09:00
parent 4d9f010ac5
commit 3ab32820e9
4 changed files with 88 additions and 71 deletions

View File

@ -170,8 +170,9 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
}
};
// 🆕 disabledFields 체크
const isFieldDisabled = props.disabledFields?.includes(columnName) || (component as any).readonly;
// 🆕 disabledFields 체크 + readonly 체크
const isFieldDisabled = props.disabledFields?.includes(columnName) || (component as any).disabled;
const isFieldReadonly = (component as any).readonly || (component as any).componentConfig?.readonly;
return (
<CategorySelectComponent
@ -182,6 +183,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
placeholder={component.componentConfig?.placeholder || "선택하세요"}
required={(component as any).required}
disabled={isFieldDisabled}
readonly={isFieldReadonly}
className="w-full"
/>
);

View File

@ -52,6 +52,10 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
menuObjid, // 🆕 메뉴 OBJID
...props
}) => {
// 🆕 읽기전용/비활성화 상태 확인
const isReadonly = (component as any).readonly || (props as any).readonly || componentConfig?.readonly || false;
const isDisabled = (component as any).disabled || (props as any).disabled || componentConfig?.disabled || false;
const isFieldDisabled = isDesignMode || isReadonly || isDisabled;
// 화면 컨텍스트 (데이터 제공자로 등록)
const screenContext = useScreenContextOptional();
@ -327,7 +331,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
// 클릭 이벤트 핸들러 (React Query로 간소화)
const handleToggle = () => {
if (isDesignMode) return;
if (isFieldDisabled) return; // 🆕 읽기전용/비활성화 상태에서는 토글 불가
// React Query가 자동으로 캐시 관리하므로 수동 새로고침 불필요
setIsOpen(!isOpen);
@ -425,7 +429,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
value={option.value}
checked={selectedValue === option.value}
onChange={() => handleOptionSelect(option.value, option.label)}
disabled={isDesignMode}
disabled={isFieldDisabled}
className="border-input text-primary focus:ring-ring h-4 w-4"
/>
<span className="text-sm">{option.label}</span>
@ -456,12 +460,14 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
placeholder="코드 또는 코드명 입력..."
className={cn(
"h-10 w-full rounded-lg border border-gray-300 bg-white px-3 py-2 transition-all outline-none",
!isDesignMode && "hover:border-orange-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-200",
!isFieldDisabled && "hover:border-orange-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-200",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
readOnly={isDesignMode}
readOnly={isFieldDisabled}
disabled={isFieldDisabled}
/>
{isOpen && !isDesignMode && filteredOptions.length > 0 && (
{isOpen && !isFieldDisabled && filteredOptions.length > 0 && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
{filteredOptions.map((option, index) => (
<div
@ -490,13 +496,14 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"flex h-10 w-full cursor-pointer items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
!isDesignMode && "hover:border-orange-400",
"flex h-10 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
!isFieldDisabled && "cursor-pointer hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isOpen && "border-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
onClick={handleToggle}
style={{ pointerEvents: isDesignMode ? "none" : "auto" }}
style={{ pointerEvents: isFieldDisabled ? "none" : "auto" }}
>
<span className={selectedLabel ? "text-gray-900" : "text-gray-500"}>{selectedLabel || placeholder}</span>
<svg
@ -508,7 +515,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
{isOpen && !isDesignMode && (
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
{isLoadingCodes ? (
<div className="bg-white px-3 py-2 text-gray-900"> ...</div>
@ -538,8 +545,9 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div
className={cn(
"box-border flex h-full w-full flex-wrap gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2",
!isDesignMode && "hover:border-orange-400",
!isFieldDisabled && "hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
>
{selectedValues.map((val, idx) => {
@ -567,8 +575,9 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
type="text"
placeholder={selectedValues.length > 0 ? "" : placeholder}
className="min-w-[100px] flex-1 border-none bg-transparent outline-none"
onClick={() => setIsOpen(true)}
readOnly={isDesignMode}
onClick={() => !isFieldDisabled && setIsOpen(true)}
readOnly={isFieldDisabled}
disabled={isFieldDisabled}
/>
</div>
</div>
@ -589,19 +598,22 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
type="text"
value={searchQuery}
onChange={(e) => {
if (isFieldDisabled) return;
setSearchQuery(e.target.value);
setIsOpen(true);
}}
onFocus={() => setIsOpen(true)}
onFocus={() => !isFieldDisabled && setIsOpen(true)}
placeholder={placeholder}
className={cn(
"h-10 w-full rounded-lg border border-gray-300 bg-white px-3 py-2 transition-all outline-none",
!isDesignMode && "hover:border-orange-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-200",
!isFieldDisabled && "hover:border-orange-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-200",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
readOnly={isDesignMode}
readOnly={isFieldDisabled}
disabled={isFieldDisabled}
/>
{isOpen && !isDesignMode && filteredOptions.length > 0 && (
{isOpen && !isFieldDisabled && filteredOptions.length > 0 && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
{filteredOptions.map((option, index) => (
<div
@ -632,13 +644,14 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"flex h-10 w-full cursor-pointer items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
!isDesignMode && "hover:border-orange-400",
"flex h-10 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
!isFieldDisabled && "cursor-pointer hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isOpen && "border-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
onClick={handleToggle}
style={{ pointerEvents: isDesignMode ? "none" : "auto" }}
style={{ pointerEvents: isFieldDisabled ? "none" : "auto" }}
>
<span className={selectedLabel ? "text-gray-900" : "text-gray-500"}>{selectedLabel || placeholder}</span>
<svg
@ -650,7 +663,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
{isOpen && !isDesignMode && (
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 w-full rounded-md border border-gray-300 bg-white shadow-lg">
<input
type="text"
@ -690,12 +703,13 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div
className={cn(
"box-border flex w-full flex-wrap items-center gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2",
!isDesignMode && "hover:border-orange-400",
!isFieldDisabled && "hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
onClick={() => !isDesignMode && setIsOpen(true)}
onClick={() => !isFieldDisabled && setIsOpen(true)}
style={{
pointerEvents: isDesignMode ? "none" : "auto",
pointerEvents: isFieldDisabled ? "none" : "auto",
height: "100%"
}}
>
@ -726,7 +740,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<span className="text-gray-500">{placeholder}</span>
)}
</div>
{isOpen && !isDesignMode && (
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
{(isLoadingCodes || isLoadingCategories) ? (
<div className="bg-white px-3 py-2 text-gray-900"> ...</div>
@ -789,13 +803,14 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"flex h-10 w-full cursor-pointer items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
!isDesignMode && "hover:border-orange-400",
"flex h-10 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
!isFieldDisabled && "cursor-pointer hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isOpen && "border-orange-500",
isFieldDisabled && "bg-gray-100 cursor-not-allowed",
)}
onClick={handleToggle}
style={{ pointerEvents: isDesignMode ? "none" : "auto" }}
style={{ pointerEvents: isFieldDisabled ? "none" : "auto" }}
>
<span className={selectedLabel ? "text-gray-900" : "text-gray-500"}>{selectedLabel || placeholder}</span>
<svg
@ -807,7 +822,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
{isOpen && !isDesignMode && (
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
{isLoadingCodes ? (
<div className="bg-white px-3 py-2 text-gray-900"> ...</div>

View File

@ -60,7 +60,7 @@
"leaflet": "^1.9.4",
"lucide-react": "^0.525.0",
"mammoth": "^1.11.0",
"next": "15.4.4",
"next": "^15.4.8",
"react": "19.1.0",
"react-day-picker": "^9.11.1",
"react-dnd": "^16.0.1",
@ -1145,9 +1145,9 @@
}
},
"node_modules/@next/env": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.4.tgz",
"integrity": "sha512-SJKOOkULKENyHSYXE5+KiFU6itcIb6wSBjgM92meK0HVKpo94dNOLZVdLLuS7/BxImROkGoPsjR4EnuDucqiiA==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.8.tgz",
"integrity": "sha512-LydLa2MDI1NMrOFSkO54mTc8iIHSttj6R6dthITky9ylXV2gCGi0bHQjVCtLGRshdRPjyh2kXbxJukDtBWQZtQ==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
@ -1161,9 +1161,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.4.tgz",
"integrity": "sha512-eVG55dnGwfUuG+TtnUCt+mEJ+8TGgul6nHEvdb8HEH7dmJIFYOCApAaFrIrxwtEq2Cdf+0m5sG1Np8cNpw9EAw==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.8.tgz",
"integrity": "sha512-Pf6zXp7yyQEn7sqMxur6+kYcywx5up1J849psyET7/8pG2gQTVMjU3NzgIt8SeEP5to3If/SaWmaA6H6ysBr1A==",
"cpu": [
"arm64"
],
@ -1177,9 +1177,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.4.tgz",
"integrity": "sha512-zqG+/8apsu49CltEj4NAmCGZvHcZbOOOsNoTVeIXphYWIbE4l6A/vuQHyqll0flU2o3dmYCXsBW5FmbrGDgljQ==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.8.tgz",
"integrity": "sha512-xla6AOfz68a6kq3gRQccWEvFC/VRGJmA/QuSLENSO7CZX5WIEkSz7r1FdXUjtGCQ1c2M+ndUAH7opdfLK1PQbw==",
"cpu": [
"x64"
],
@ -1193,9 +1193,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.4.tgz",
"integrity": "sha512-LRD4l2lq4R+2QCHBQVC0wjxxkLlALGJCwigaJ5FSRSqnje+MRKHljQNZgDCaKUZQzO/TXxlmUdkZP/X3KNGZaw==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.8.tgz",
"integrity": "sha512-y3fmp+1Px/SJD+5ntve5QLZnGLycsxsVPkTzAc3zUiXYSOlTPqT8ynfmt6tt4fSo1tAhDPmryXpYKEAcoAPDJw==",
"cpu": [
"arm64"
],
@ -1209,9 +1209,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.4.tgz",
"integrity": "sha512-LsGUCTvuZ0690fFWerA4lnQvjkYg9gHo12A3wiPUR4kCxbx/d+SlwmonuTH2SWZI+RVGA9VL3N0S03WTYv6bYg==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.8.tgz",
"integrity": "sha512-DX/L8VHzrr1CfwaVjBQr3GWCqNNFgyWJbeQ10Lx/phzbQo3JNAxUok1DZ8JHRGcL6PgMRgj6HylnLNndxn4Z6A==",
"cpu": [
"arm64"
],
@ -1225,9 +1225,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.4.tgz",
"integrity": "sha512-aOy5yNRpLL3wNiJVkFYl6w22hdREERNjvegE6vvtix8LHRdsTHhWTpgvcYdCK7AIDCQW5ATmzr9XkPHvSoAnvg==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.8.tgz",
"integrity": "sha512-9fLAAXKAL3xEIFdKdzG5rUSvSiZTLLTCc6JKq1z04DR4zY7DbAPcRvNm3K1inVhTiQCs19ZRAgUerHiVKMZZIA==",
"cpu": [
"x64"
],
@ -1241,9 +1241,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.4.tgz",
"integrity": "sha512-FL7OAn4UkR8hKQRGBmlHiHinzOb07tsfARdGh7v0Z0jEJ3sz8/7L5bR23ble9E6DZMabSStqlATHlSxv1fuzAg==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.8.tgz",
"integrity": "sha512-s45V7nfb5g7dbS7JK6XZDcapicVrMMvX2uYgOHP16QuKH/JA285oy6HcxlKqwUNaFY/UC6EvQ8QZUOo19cBKSA==",
"cpu": [
"x64"
],
@ -1257,9 +1257,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.4.tgz",
"integrity": "sha512-eEdNW/TXwjYhOulQh0pffTMMItWVwKCQpbziSBmgBNFZIIRn2GTXrhrewevs8wP8KXWYMx8Z+mNU0X+AfvtrRg==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.8.tgz",
"integrity": "sha512-KjgeQyOAq7t/HzAJcWPGA8X+4WY03uSCZ2Ekk98S9OgCFsb6lfBE3dbUzUuEQAN2THbwYgFfxX2yFTCMm8Kehw==",
"cpu": [
"arm64"
],
@ -1273,9 +1273,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.4.tgz",
"integrity": "sha512-SE5pYNbn/xZKMy1RE3pAs+4xD32OI4rY6mzJa4XUkp/ItZY+OMjIgilskmErt8ls/fVJ+Ihopi2QIeW6O3TrMw==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.8.tgz",
"integrity": "sha512-Exsmf/+42fWVnLMaZHzshukTBxZrSwuuLKFvqhGHJ+mC1AokqieLY/XzAl3jc/CqhXLqLY3RRjkKJ9YnLPcRWg==",
"cpu": [
"x64"
],
@ -10876,12 +10876,12 @@
"license": "MIT"
},
"node_modules/next": {
"version": "15.4.4",
"resolved": "https://registry.npmjs.org/next/-/next-15.4.4.tgz",
"integrity": "sha512-kNcubvJjOL9yUOfwtZF3HfDhuhp+kVD+FM2A6Tyua1eI/xfmY4r/8ZS913MMz+oWKDlbps/dQOWdDricuIkXLw==",
"version": "15.4.8",
"resolved": "https://registry.npmjs.org/next/-/next-15.4.8.tgz",
"integrity": "sha512-jwOXTz/bo0Pvlf20FSb6VXVeWRssA2vbvq9SdrOPEg9x8E1B27C2rQtvriAn600o9hH61kjrVRexEffv3JybuA==",
"license": "MIT",
"dependencies": {
"@next/env": "15.4.4",
"@next/env": "15.4.8",
"@swc/helpers": "0.5.15",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
@ -10894,14 +10894,14 @@
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "15.4.4",
"@next/swc-darwin-x64": "15.4.4",
"@next/swc-linux-arm64-gnu": "15.4.4",
"@next/swc-linux-arm64-musl": "15.4.4",
"@next/swc-linux-x64-gnu": "15.4.4",
"@next/swc-linux-x64-musl": "15.4.4",
"@next/swc-win32-arm64-msvc": "15.4.4",
"@next/swc-win32-x64-msvc": "15.4.4",
"@next/swc-darwin-arm64": "15.4.8",
"@next/swc-darwin-x64": "15.4.8",
"@next/swc-linux-arm64-gnu": "15.4.8",
"@next/swc-linux-arm64-musl": "15.4.8",
"@next/swc-linux-x64-gnu": "15.4.8",
"@next/swc-linux-x64-musl": "15.4.8",
"@next/swc-win32-arm64-msvc": "15.4.8",
"@next/swc-win32-x64-msvc": "15.4.8",
"sharp": "^0.34.3"
},
"peerDependencies": {

View File

@ -68,7 +68,7 @@
"leaflet": "^1.9.4",
"lucide-react": "^0.525.0",
"mammoth": "^1.11.0",
"next": "15.4.4",
"next": "^15.4.8",
"react": "19.1.0",
"react-day-picker": "^9.11.1",
"react-dnd": "^16.0.1",