@farmzone/fz-react-ui 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +167 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +167 -61
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -557,15 +557,23 @@ interface ModalHeaderProps {
|
|
|
557
557
|
ref?: Ref<HTMLDivElement>;
|
|
558
558
|
children: ReactNode;
|
|
559
559
|
className?: string;
|
|
560
|
+
style?: CSSProperties;
|
|
560
561
|
}
|
|
561
562
|
declare function ModalHeader(props: ModalHeaderProps): react.JSX.Element;
|
|
562
563
|
|
|
563
564
|
type ModalType = "detail" | "create" | "edit" | "search" | "info" | "delete" | "warning";
|
|
565
|
+
type ModalIconHeaderVariant = "default" | "system-light" | "system-dark";
|
|
566
|
+
type ModalIconHeaderSize = "sm" | "md";
|
|
564
567
|
interface ModalIconHeaderProps {
|
|
565
568
|
type: ModalType;
|
|
566
569
|
title: string;
|
|
567
570
|
description?: string;
|
|
568
571
|
onClose: () => void;
|
|
572
|
+
action?: ReactNode;
|
|
573
|
+
variant?: ModalIconHeaderVariant;
|
|
574
|
+
size?: ModalIconHeaderSize;
|
|
575
|
+
/** default / system-light: 그라디언트·아이콘 색을 primaryColor 기준으로 자동 적용 */
|
|
576
|
+
primaryColor?: string;
|
|
569
577
|
className?: string;
|
|
570
578
|
}
|
|
571
579
|
declare function ModalIconHeader(props: ModalIconHeaderProps): react.JSX.Element;
|
|
@@ -961,6 +969,7 @@ type SelectOption<P> = BaseOption<P> & {
|
|
|
961
969
|
options: Array<SelectableOption>;
|
|
962
970
|
placeholder?: string;
|
|
963
971
|
containerClassName?: string;
|
|
972
|
+
canReset?: boolean;
|
|
964
973
|
};
|
|
965
974
|
type RadioOption<P> = BaseOption<P> & {
|
|
966
975
|
type: "radio";
|
|
@@ -1049,6 +1058,7 @@ interface MultiTabBarProps {
|
|
|
1049
1058
|
onTabClick: (tabId: string) => void;
|
|
1050
1059
|
onTabClose: (tabId: string) => void;
|
|
1051
1060
|
onTabAdd?: () => void;
|
|
1061
|
+
onTabsReorder?: (tabs: Array<MultiTab>) => void;
|
|
1052
1062
|
variant?: MultiTabVariant;
|
|
1053
1063
|
primaryColor?: string;
|
|
1054
1064
|
}
|
|
@@ -1148,6 +1158,7 @@ interface SidebarProps {
|
|
|
1148
1158
|
footer?: ReactNode;
|
|
1149
1159
|
className?: string;
|
|
1150
1160
|
showCollapseButton?: boolean;
|
|
1161
|
+
collapseButtonPlacement?: "left" | "right";
|
|
1151
1162
|
onClose?: () => void;
|
|
1152
1163
|
variant?: SidebarVariant;
|
|
1153
1164
|
primaryColor?: string;
|
|
@@ -1245,6 +1256,10 @@ interface DetailModalFrameProps<T, S extends z.ZodTypeAny = z.ZodTypeAny> {
|
|
|
1245
1256
|
onDirtyChange?: (isDirty: boolean) => void;
|
|
1246
1257
|
/** 제공 시 ModalIconHeader로 렌더링 (read 모드: 이 type, edit 모드: "edit" 자동 적용) */
|
|
1247
1258
|
headerType?: ModalType;
|
|
1259
|
+
/** ModalIconHeader 스타일 변형 */
|
|
1260
|
+
headerIconVariant?: ModalIconHeaderVariant;
|
|
1261
|
+
/** ModalIconHeader 사이즈 */
|
|
1262
|
+
headerIconSize?: ModalIconHeaderSize;
|
|
1248
1263
|
}
|
|
1249
1264
|
declare function DetailModalFrame<T, S extends z.ZodTypeAny = z.ZodTypeAny>(props: DetailModalFrameProps<T, S>): react.JSX.Element;
|
|
1250
1265
|
|
package/dist/index.d.ts
CHANGED
|
@@ -557,15 +557,23 @@ interface ModalHeaderProps {
|
|
|
557
557
|
ref?: Ref<HTMLDivElement>;
|
|
558
558
|
children: ReactNode;
|
|
559
559
|
className?: string;
|
|
560
|
+
style?: CSSProperties;
|
|
560
561
|
}
|
|
561
562
|
declare function ModalHeader(props: ModalHeaderProps): react.JSX.Element;
|
|
562
563
|
|
|
563
564
|
type ModalType = "detail" | "create" | "edit" | "search" | "info" | "delete" | "warning";
|
|
565
|
+
type ModalIconHeaderVariant = "default" | "system-light" | "system-dark";
|
|
566
|
+
type ModalIconHeaderSize = "sm" | "md";
|
|
564
567
|
interface ModalIconHeaderProps {
|
|
565
568
|
type: ModalType;
|
|
566
569
|
title: string;
|
|
567
570
|
description?: string;
|
|
568
571
|
onClose: () => void;
|
|
572
|
+
action?: ReactNode;
|
|
573
|
+
variant?: ModalIconHeaderVariant;
|
|
574
|
+
size?: ModalIconHeaderSize;
|
|
575
|
+
/** default / system-light: 그라디언트·아이콘 색을 primaryColor 기준으로 자동 적용 */
|
|
576
|
+
primaryColor?: string;
|
|
569
577
|
className?: string;
|
|
570
578
|
}
|
|
571
579
|
declare function ModalIconHeader(props: ModalIconHeaderProps): react.JSX.Element;
|
|
@@ -961,6 +969,7 @@ type SelectOption<P> = BaseOption<P> & {
|
|
|
961
969
|
options: Array<SelectableOption>;
|
|
962
970
|
placeholder?: string;
|
|
963
971
|
containerClassName?: string;
|
|
972
|
+
canReset?: boolean;
|
|
964
973
|
};
|
|
965
974
|
type RadioOption<P> = BaseOption<P> & {
|
|
966
975
|
type: "radio";
|
|
@@ -1049,6 +1058,7 @@ interface MultiTabBarProps {
|
|
|
1049
1058
|
onTabClick: (tabId: string) => void;
|
|
1050
1059
|
onTabClose: (tabId: string) => void;
|
|
1051
1060
|
onTabAdd?: () => void;
|
|
1061
|
+
onTabsReorder?: (tabs: Array<MultiTab>) => void;
|
|
1052
1062
|
variant?: MultiTabVariant;
|
|
1053
1063
|
primaryColor?: string;
|
|
1054
1064
|
}
|
|
@@ -1148,6 +1158,7 @@ interface SidebarProps {
|
|
|
1148
1158
|
footer?: ReactNode;
|
|
1149
1159
|
className?: string;
|
|
1150
1160
|
showCollapseButton?: boolean;
|
|
1161
|
+
collapseButtonPlacement?: "left" | "right";
|
|
1151
1162
|
onClose?: () => void;
|
|
1152
1163
|
variant?: SidebarVariant;
|
|
1153
1164
|
primaryColor?: string;
|
|
@@ -1245,6 +1256,10 @@ interface DetailModalFrameProps<T, S extends z.ZodTypeAny = z.ZodTypeAny> {
|
|
|
1245
1256
|
onDirtyChange?: (isDirty: boolean) => void;
|
|
1246
1257
|
/** 제공 시 ModalIconHeader로 렌더링 (read 모드: 이 type, edit 모드: "edit" 자동 적용) */
|
|
1247
1258
|
headerType?: ModalType;
|
|
1259
|
+
/** ModalIconHeader 스타일 변형 */
|
|
1260
|
+
headerIconVariant?: ModalIconHeaderVariant;
|
|
1261
|
+
/** ModalIconHeader 사이즈 */
|
|
1262
|
+
headerIconSize?: ModalIconHeaderSize;
|
|
1248
1263
|
}
|
|
1249
1264
|
declare function DetailModalFrame<T, S extends z.ZodTypeAny = z.ZodTypeAny>(props: DetailModalFrameProps<T, S>): react.JSX.Element;
|
|
1250
1265
|
|
package/dist/index.js
CHANGED
|
@@ -3444,36 +3444,100 @@ var MODAL_ICONS = {
|
|
|
3444
3444
|
delete: Trash2,
|
|
3445
3445
|
warning: TriangleAlert
|
|
3446
3446
|
};
|
|
3447
|
+
var VARIANT_CONFIG = {
|
|
3448
|
+
default: {
|
|
3449
|
+
container: "bg-gradient-to-r from-blue-50 to-indigo-50 border-blue-100",
|
|
3450
|
+
iconBg: "bg-blue-100 rounded-full",
|
|
3451
|
+
iconColor: "text-main",
|
|
3452
|
+
titleColor: "text-gray-900",
|
|
3453
|
+
descColor: "text-gray-500",
|
|
3454
|
+
closeBtn: "text-gray-400 group-hover:text-gray-600"
|
|
3455
|
+
},
|
|
3456
|
+
"system-light": {
|
|
3457
|
+
container: "bg-gray-50 border-gray-200",
|
|
3458
|
+
iconBg: "bg-white border border-gray-200 shadow-sm rounded-lg",
|
|
3459
|
+
iconColor: "text-slate-600",
|
|
3460
|
+
titleColor: "text-gray-900",
|
|
3461
|
+
descColor: "text-gray-500",
|
|
3462
|
+
closeBtn: "text-gray-400 group-hover:text-gray-600"
|
|
3463
|
+
},
|
|
3464
|
+
"system-dark": {
|
|
3465
|
+
container: "bg-slate-800 border-slate-700",
|
|
3466
|
+
iconBg: "bg-slate-700 border border-slate-600 shadow-sm rounded-lg",
|
|
3467
|
+
iconColor: "text-slate-300",
|
|
3468
|
+
titleColor: "text-slate-100",
|
|
3469
|
+
descColor: "text-slate-400",
|
|
3470
|
+
closeBtn: "text-slate-500 group-hover:text-slate-300"
|
|
3471
|
+
}
|
|
3472
|
+
};
|
|
3473
|
+
var SIZE_CONFIG = {
|
|
3474
|
+
md: {
|
|
3475
|
+
padding: "px-6 py-5",
|
|
3476
|
+
iconBox: "w-10 h-10",
|
|
3477
|
+
iconSize: 20,
|
|
3478
|
+
gap: "gap-3",
|
|
3479
|
+
titleSize: "text-xl font-bold",
|
|
3480
|
+
descSize: "text-sm mt-0.5",
|
|
3481
|
+
closeBtnBox: "w-10 h-10",
|
|
3482
|
+
closeIconSize: 20
|
|
3483
|
+
},
|
|
3484
|
+
sm: {
|
|
3485
|
+
padding: "px-4 py-4",
|
|
3486
|
+
iconBox: "w-8 h-8",
|
|
3487
|
+
iconSize: 16,
|
|
3488
|
+
gap: "gap-2.5",
|
|
3489
|
+
titleSize: "text-lg font-bold",
|
|
3490
|
+
descSize: "text-sm mt-0.5",
|
|
3491
|
+
closeBtnBox: "w-8 h-8",
|
|
3492
|
+
closeIconSize: 16
|
|
3493
|
+
}
|
|
3494
|
+
};
|
|
3447
3495
|
function ModalIconHeader(props) {
|
|
3448
|
-
const {
|
|
3496
|
+
const {
|
|
3497
|
+
type,
|
|
3498
|
+
title,
|
|
3499
|
+
description,
|
|
3500
|
+
onClose,
|
|
3501
|
+
action,
|
|
3502
|
+
variant = "default",
|
|
3503
|
+
size: size2 = "md",
|
|
3504
|
+
primaryColor,
|
|
3505
|
+
className
|
|
3506
|
+
} = props;
|
|
3449
3507
|
const Icon2 = MODAL_ICONS[type];
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
type: "button",
|
|
3469
|
-
onClick: onClose,
|
|
3470
|
-
className: "flex items-center justify-center w-10 h-10 rounded-full transition-colors group cursor-pointer hover:bg-black/5 shrink-0",
|
|
3471
|
-
children: /* @__PURE__ */ jsx(X, { size: 20, className: "text-gray-400 group-hover:text-gray-600 transition-colors" })
|
|
3472
|
-
}
|
|
3473
|
-
)
|
|
3508
|
+
const v = VARIANT_CONFIG[variant];
|
|
3509
|
+
const s = SIZE_CONFIG[size2];
|
|
3510
|
+
const hasColor = !!primaryColor;
|
|
3511
|
+
const isDark = variant === "system-dark";
|
|
3512
|
+
const containerStyle = hasColor && variant === "default" ? {
|
|
3513
|
+
background: `linear-gradient(to right, color-mix(in srgb, ${primaryColor} 6%, white), color-mix(in srgb, ${primaryColor} 12%, white))`,
|
|
3514
|
+
borderColor: `color-mix(in srgb, ${primaryColor} 25%, transparent)`
|
|
3515
|
+
} : void 0;
|
|
3516
|
+
const iconBgStyle = hasColor ? {
|
|
3517
|
+
backgroundColor: isDark ? `color-mix(in srgb, ${primaryColor} 20%, #334155)` : `color-mix(in srgb, ${primaryColor} 15%, white)`
|
|
3518
|
+
} : void 0;
|
|
3519
|
+
const iconColorStyle = hasColor && !isDark ? { color: primaryColor } : void 0;
|
|
3520
|
+
return /* @__PURE__ */ jsx(ModalHeader, { className: cn("p-0 text-left space-y-0", v.container, className), style: containerStyle, children: /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between", s.padding), children: [
|
|
3521
|
+
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center", s.gap), children: [
|
|
3522
|
+
/* @__PURE__ */ jsx("div", { className: cn("flex items-center justify-center shrink-0", s.iconBox, v.iconBg), style: iconBgStyle, children: /* @__PURE__ */ jsx(Icon2, { size: s.iconSize, className: hasColor && !isDark ? void 0 : v.iconColor, style: iconColorStyle }) }),
|
|
3523
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3524
|
+
/* @__PURE__ */ jsx("h2", { className: cn(s.titleSize, v.titleColor), children: title }),
|
|
3525
|
+
description && /* @__PURE__ */ jsx("p", { className: cn(s.descSize, v.descColor), children: description })
|
|
3474
3526
|
] })
|
|
3475
|
-
}
|
|
3476
|
-
|
|
3527
|
+
] }),
|
|
3528
|
+
action ?? /* @__PURE__ */ jsx(
|
|
3529
|
+
"button",
|
|
3530
|
+
{
|
|
3531
|
+
type: "button",
|
|
3532
|
+
onClick: onClose,
|
|
3533
|
+
className: cn(
|
|
3534
|
+
"flex items-center justify-center rounded-full transition-colors group cursor-pointer hover:bg-black/5 shrink-0",
|
|
3535
|
+
s.closeBtnBox
|
|
3536
|
+
),
|
|
3537
|
+
children: /* @__PURE__ */ jsx(X, { size: s.closeIconSize, className: cn("transition-colors", v.closeBtn) })
|
|
3538
|
+
}
|
|
3539
|
+
)
|
|
3540
|
+
] }) });
|
|
3477
3541
|
}
|
|
3478
3542
|
function Modal(props) {
|
|
3479
3543
|
const {
|
|
@@ -7693,7 +7757,7 @@ function PageFilter(props) {
|
|
|
7693
7757
|
onChange: handleSelectChange(optionKey),
|
|
7694
7758
|
options: option.options,
|
|
7695
7759
|
placeholder: "\uC120\uD0DD",
|
|
7696
|
-
canReset: true,
|
|
7760
|
+
canReset: option.canReset ?? true,
|
|
7697
7761
|
containerClassName: option.containerClassName ?? "w-30"
|
|
7698
7762
|
}
|
|
7699
7763
|
) }, String(optionKey));
|
|
@@ -7844,16 +7908,24 @@ function easedFade(dir, opacity) {
|
|
|
7844
7908
|
return `linear-gradient(${dir}, ${c(1)} 0%, ${c(0.72)} 20%, ${c(0.38)} 45%, ${c(0.1)} 70%, transparent 100%)`;
|
|
7845
7909
|
}
|
|
7846
7910
|
function MultiTabBar(props) {
|
|
7847
|
-
const {
|
|
7911
|
+
const {
|
|
7912
|
+
tabs,
|
|
7913
|
+
activeTabId,
|
|
7914
|
+
onTabClick,
|
|
7915
|
+
onTabClose,
|
|
7916
|
+
onTabAdd,
|
|
7917
|
+
onTabsReorder,
|
|
7918
|
+
variant = "light",
|
|
7919
|
+
primaryColor
|
|
7920
|
+
} = props;
|
|
7848
7921
|
const s = VARIANT_STYLES[variant];
|
|
7849
7922
|
const scrollRef = useRef(null);
|
|
7850
7923
|
const tabRefs = useRef(/* @__PURE__ */ new Map());
|
|
7851
7924
|
const [showLeftFade, setShowLeftFade] = useState(false);
|
|
7852
7925
|
const [showRightFade, setShowRightFade] = useState(false);
|
|
7853
|
-
const
|
|
7854
|
-
const
|
|
7855
|
-
const
|
|
7856
|
-
const dragScrollLeft = useRef(0);
|
|
7926
|
+
const [draggingId, setDraggingId] = useState(null);
|
|
7927
|
+
const [dropTargetId, setDropTargetId] = useState(null);
|
|
7928
|
+
const [dropSide, setDropSide] = useState("before");
|
|
7857
7929
|
useEffect(() => {
|
|
7858
7930
|
if (!activeTabId || !scrollRef.current) return;
|
|
7859
7931
|
const el = tabRefs.current.get(activeTabId);
|
|
@@ -7881,23 +7953,6 @@ function MultiTabBar(props) {
|
|
|
7881
7953
|
if (scrollRef.current) obs.observe(scrollRef.current);
|
|
7882
7954
|
return () => obs.disconnect();
|
|
7883
7955
|
}, [tabs]);
|
|
7884
|
-
const handleMouseDown = (e) => {
|
|
7885
|
-
if (!scrollRef.current) return;
|
|
7886
|
-
isDragging.current = true;
|
|
7887
|
-
hasDragged.current = false;
|
|
7888
|
-
dragStartX.current = e.pageX - scrollRef.current.getBoundingClientRect().left;
|
|
7889
|
-
dragScrollLeft.current = scrollRef.current.scrollLeft;
|
|
7890
|
-
};
|
|
7891
|
-
const handleMouseMove = (e) => {
|
|
7892
|
-
if (!isDragging.current || !scrollRef.current) return;
|
|
7893
|
-
const x = e.pageX - scrollRef.current.getBoundingClientRect().left;
|
|
7894
|
-
const walk = x - dragStartX.current;
|
|
7895
|
-
if (Math.abs(walk) > 4) hasDragged.current = true;
|
|
7896
|
-
scrollRef.current.scrollLeft = dragScrollLeft.current - walk;
|
|
7897
|
-
};
|
|
7898
|
-
const handleStopDrag = () => {
|
|
7899
|
-
isDragging.current = false;
|
|
7900
|
-
};
|
|
7901
7956
|
useEffect(() => {
|
|
7902
7957
|
const el = scrollRef.current;
|
|
7903
7958
|
if (!el) return;
|
|
@@ -7908,6 +7963,46 @@ function MultiTabBar(props) {
|
|
|
7908
7963
|
el.addEventListener("wheel", onWheel, { passive: false });
|
|
7909
7964
|
return () => el.removeEventListener("wheel", onWheel);
|
|
7910
7965
|
}, []);
|
|
7966
|
+
const handleDragStart = (e, tabId) => {
|
|
7967
|
+
setDraggingId(tabId);
|
|
7968
|
+
e.dataTransfer.effectAllowed = "move";
|
|
7969
|
+
};
|
|
7970
|
+
const handleDragOver = (e, tabId) => {
|
|
7971
|
+
e.preventDefault();
|
|
7972
|
+
if (tabId === draggingId) return;
|
|
7973
|
+
e.dataTransfer.dropEffect = "move";
|
|
7974
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
7975
|
+
setDropSide(e.clientX < rect.left + rect.width / 2 ? "before" : "after");
|
|
7976
|
+
setDropTargetId(tabId);
|
|
7977
|
+
};
|
|
7978
|
+
const handleDrop = (e, targetTabId) => {
|
|
7979
|
+
e.preventDefault();
|
|
7980
|
+
if (!draggingId || draggingId === targetTabId) {
|
|
7981
|
+
setDraggingId(null);
|
|
7982
|
+
setDropTargetId(null);
|
|
7983
|
+
return;
|
|
7984
|
+
}
|
|
7985
|
+
if (onTabsReorder) {
|
|
7986
|
+
const fromIdx = tabs.findIndex((t) => t.id === draggingId);
|
|
7987
|
+
if (fromIdx !== -1) {
|
|
7988
|
+
const newTabs = [...tabs];
|
|
7989
|
+
const moved = newTabs.splice(fromIdx, 1)[0];
|
|
7990
|
+
let insertIdx = newTabs.findIndex((t) => t.id === targetTabId);
|
|
7991
|
+
if (insertIdx !== -1) {
|
|
7992
|
+
if (dropSide === "after") insertIdx += 1;
|
|
7993
|
+
newTabs.splice(insertIdx, 0, moved);
|
|
7994
|
+
onTabsReorder(newTabs);
|
|
7995
|
+
}
|
|
7996
|
+
}
|
|
7997
|
+
}
|
|
7998
|
+
setDraggingId(null);
|
|
7999
|
+
setDropTargetId(null);
|
|
8000
|
+
};
|
|
8001
|
+
const handleDragEnd = () => {
|
|
8002
|
+
setDraggingId(null);
|
|
8003
|
+
setDropTargetId(null);
|
|
8004
|
+
};
|
|
8005
|
+
const showPlus = !!onTabAdd;
|
|
7911
8006
|
if (tabs.length === 0) return null;
|
|
7912
8007
|
return /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 w-full overflow-hidden ${s.container}`, children: /* @__PURE__ */ jsxs("div", { className: "relative flex items-stretch", children: [
|
|
7913
8008
|
showLeftFade && /* @__PURE__ */ jsx(
|
|
@@ -7922,7 +8017,7 @@ function MultiTabBar(props) {
|
|
|
7922
8017
|
{
|
|
7923
8018
|
className: "absolute top-0 bottom-0 w-10 pointer-events-none z-10",
|
|
7924
8019
|
style: {
|
|
7925
|
-
right: PLUS_BTN_WIDTH,
|
|
8020
|
+
right: showPlus ? PLUS_BTN_WIDTH : 0,
|
|
7926
8021
|
background: easedFade("to left", s.fadeOpacity)
|
|
7927
8022
|
}
|
|
7928
8023
|
}
|
|
@@ -7934,12 +8029,10 @@ function MultiTabBar(props) {
|
|
|
7934
8029
|
className: `flex-1 min-w-0 flex items-end gap-0.5 ${s.scrollPadding} overflow-x-auto [&::-webkit-scrollbar]:hidden`,
|
|
7935
8030
|
style: { scrollbarWidth: "none" },
|
|
7936
8031
|
onScroll: updateFades,
|
|
7937
|
-
onMouseDown: handleMouseDown,
|
|
7938
|
-
onMouseMove: handleMouseMove,
|
|
7939
|
-
onMouseUp: handleStopDrag,
|
|
7940
|
-
onMouseLeave: handleStopDrag,
|
|
7941
8032
|
children: tabs.map((tab) => {
|
|
7942
8033
|
const isActive = tab.id === activeTabId;
|
|
8034
|
+
const isDraggingThis = tab.id === draggingId;
|
|
8035
|
+
const isDropTarget = dropTargetId === tab.id;
|
|
7943
8036
|
return /* @__PURE__ */ jsxs(
|
|
7944
8037
|
"div",
|
|
7945
8038
|
{
|
|
@@ -7947,15 +8040,23 @@ function MultiTabBar(props) {
|
|
|
7947
8040
|
if (el) tabRefs.current.set(tab.id, el);
|
|
7948
8041
|
else tabRefs.current.delete(tab.id);
|
|
7949
8042
|
},
|
|
8043
|
+
draggable: !!onTabsReorder,
|
|
7950
8044
|
onClick: () => {
|
|
7951
|
-
if (hasDragged.current) return;
|
|
7952
8045
|
if (!isActive) onTabClick(tab.id);
|
|
7953
8046
|
},
|
|
8047
|
+
onDragStart: (e) => handleDragStart(e, tab.id),
|
|
8048
|
+
onDragOver: (e) => handleDragOver(e, tab.id),
|
|
8049
|
+
onDrop: (e) => handleDrop(e, tab.id),
|
|
8050
|
+
onDragEnd: handleDragEnd,
|
|
7954
8051
|
className: `
|
|
7955
8052
|
group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
|
|
7956
|
-
${s.rounded} border border-b-0
|
|
8053
|
+
${s.rounded} border border-b-0 select-none
|
|
7957
8054
|
transition-colors duration-100
|
|
7958
8055
|
${isActive ? s.activeTab : s.inactiveTab}
|
|
8056
|
+
${onTabsReorder ? "cursor-grab" : "cursor-pointer"}
|
|
8057
|
+
${isDraggingThis ? "opacity-40" : ""}
|
|
8058
|
+
${isDropTarget && dropSide === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""}
|
|
8059
|
+
${isDropTarget && dropSide === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}
|
|
7959
8060
|
`,
|
|
7960
8061
|
children: [
|
|
7961
8062
|
isActive && /* @__PURE__ */ jsx(
|
|
@@ -7995,7 +8096,7 @@ function MultiTabBar(props) {
|
|
|
7995
8096
|
})
|
|
7996
8097
|
}
|
|
7997
8098
|
),
|
|
7998
|
-
|
|
8099
|
+
showPlus && /* @__PURE__ */ jsx(
|
|
7999
8100
|
"div",
|
|
8000
8101
|
{
|
|
8001
8102
|
className: `flex-shrink-0 flex items-center justify-center ${s.plusBtnArea}`,
|
|
@@ -8992,6 +9093,7 @@ function Sidebar(props) {
|
|
|
8992
9093
|
footer,
|
|
8993
9094
|
className,
|
|
8994
9095
|
showCollapseButton = false,
|
|
9096
|
+
collapseButtonPlacement = "right",
|
|
8995
9097
|
variant = "light",
|
|
8996
9098
|
primaryColor
|
|
8997
9099
|
} = props;
|
|
@@ -9078,7 +9180,7 @@ function Sidebar(props) {
|
|
|
9078
9180
|
"button",
|
|
9079
9181
|
{
|
|
9080
9182
|
onClick: () => setIsCollapsed((prev) => !prev),
|
|
9081
|
-
className: `absolute top-4
|
|
9183
|
+
className: `absolute top-4 z-20 w-6.5 h-6.5 rounded-full flex items-center justify-center transition-colors cursor-pointer ${s.collapseBtn} ${collapseButtonPlacement === "left" ? "left-2" : "right-2"}`,
|
|
9082
9184
|
children: isCollapsed ? /* @__PURE__ */ jsx(PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsx(PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
|
|
9083
9185
|
}
|
|
9084
9186
|
),
|
|
@@ -9498,7 +9600,9 @@ function DetailModalFrame(props) {
|
|
|
9498
9600
|
renderExtraContent,
|
|
9499
9601
|
renderFooterExtra,
|
|
9500
9602
|
onDirtyChange,
|
|
9501
|
-
headerType
|
|
9603
|
+
headerType,
|
|
9604
|
+
headerIconVariant,
|
|
9605
|
+
headerIconSize
|
|
9502
9606
|
} = props;
|
|
9503
9607
|
const controller = useDetailController({ mode, onModeChange });
|
|
9504
9608
|
useEffect(() => {
|
|
@@ -9542,7 +9646,9 @@ function DetailModalFrame(props) {
|
|
|
9542
9646
|
{
|
|
9543
9647
|
type: isEditMode ? "edit" : headerType,
|
|
9544
9648
|
title,
|
|
9545
|
-
onClose: handleClose
|
|
9649
|
+
onClose: handleClose,
|
|
9650
|
+
variant: headerIconVariant,
|
|
9651
|
+
size: headerIconSize
|
|
9546
9652
|
}
|
|
9547
9653
|
) : /* @__PURE__ */ jsx(ModalHeader, { className: "flex flex-row items-center justify-between", children: /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900", children: title }) }),
|
|
9548
9654
|
/* @__PURE__ */ jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
|