@farmzone/fz-react-ui 1.0.8 → 1.0.10
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 +190 -62
- 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 +190 -62
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
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-[#ededed] border-gray-200",
|
|
3458
|
+
iconBg: "bg-white border border-gray-200 shadow-xs 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 {
|
|
@@ -7692,8 +7756,8 @@ function PageFilter(props) {
|
|
|
7692
7756
|
value: currentValue,
|
|
7693
7757
|
onChange: handleSelectChange(optionKey),
|
|
7694
7758
|
options: option.options,
|
|
7695
|
-
placeholder: "\uC120\uD0DD",
|
|
7696
|
-
canReset: true,
|
|
7759
|
+
placeholder: option.placeholder || "\uC120\uD0DD",
|
|
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,64 @@ 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
|
+
e.stopPropagation();
|
|
7981
|
+
if (!draggingId || draggingId === targetTabId) {
|
|
7982
|
+
setDraggingId(null);
|
|
7983
|
+
setDropTargetId(null);
|
|
7984
|
+
return;
|
|
7985
|
+
}
|
|
7986
|
+
if (onTabsReorder) {
|
|
7987
|
+
const fromIdx = tabs.findIndex((t) => t.id === draggingId);
|
|
7988
|
+
if (fromIdx !== -1) {
|
|
7989
|
+
const newTabs = [...tabs];
|
|
7990
|
+
const moved = newTabs.splice(fromIdx, 1)[0];
|
|
7991
|
+
let insertIdx = newTabs.findIndex((t) => t.id === targetTabId);
|
|
7992
|
+
if (insertIdx !== -1) {
|
|
7993
|
+
if (dropSide === "after") insertIdx += 1;
|
|
7994
|
+
newTabs.splice(insertIdx, 0, moved);
|
|
7995
|
+
onTabsReorder(newTabs);
|
|
7996
|
+
}
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
setDraggingId(null);
|
|
8000
|
+
setDropTargetId(null);
|
|
8001
|
+
};
|
|
8002
|
+
const handleContainerDrop = (e) => {
|
|
8003
|
+
e.preventDefault();
|
|
8004
|
+
if (!draggingId || !onTabsReorder) {
|
|
8005
|
+
setDraggingId(null);
|
|
8006
|
+
setDropTargetId(null);
|
|
8007
|
+
return;
|
|
8008
|
+
}
|
|
8009
|
+
const fromIdx = tabs.findIndex((t) => t.id === draggingId);
|
|
8010
|
+
if (fromIdx !== -1 && fromIdx < tabs.length - 1) {
|
|
8011
|
+
const newTabs = [...tabs];
|
|
8012
|
+
const moved = newTabs.splice(fromIdx, 1)[0];
|
|
8013
|
+
newTabs.push(moved);
|
|
8014
|
+
onTabsReorder(newTabs);
|
|
8015
|
+
}
|
|
8016
|
+
setDraggingId(null);
|
|
8017
|
+
setDropTargetId(null);
|
|
8018
|
+
};
|
|
8019
|
+
const handleDragEnd = () => {
|
|
8020
|
+
setDraggingId(null);
|
|
8021
|
+
setDropTargetId(null);
|
|
8022
|
+
};
|
|
8023
|
+
const showPlus = !!onTabAdd;
|
|
7911
8024
|
if (tabs.length === 0) return null;
|
|
7912
8025
|
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
8026
|
showLeftFade && /* @__PURE__ */ jsx(
|
|
@@ -7922,7 +8035,7 @@ function MultiTabBar(props) {
|
|
|
7922
8035
|
{
|
|
7923
8036
|
className: "absolute top-0 bottom-0 w-10 pointer-events-none z-10",
|
|
7924
8037
|
style: {
|
|
7925
|
-
right: PLUS_BTN_WIDTH,
|
|
8038
|
+
right: showPlus ? PLUS_BTN_WIDTH : 0,
|
|
7926
8039
|
background: easedFade("to left", s.fadeOpacity)
|
|
7927
8040
|
}
|
|
7928
8041
|
}
|
|
@@ -7934,12 +8047,14 @@ function MultiTabBar(props) {
|
|
|
7934
8047
|
className: `flex-1 min-w-0 flex items-end gap-0.5 ${s.scrollPadding} overflow-x-auto [&::-webkit-scrollbar]:hidden`,
|
|
7935
8048
|
style: { scrollbarWidth: "none" },
|
|
7936
8049
|
onScroll: updateFades,
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
8050
|
+
onDragOver: (e) => {
|
|
8051
|
+
if (draggingId) e.preventDefault();
|
|
8052
|
+
},
|
|
8053
|
+
onDrop: handleContainerDrop,
|
|
7941
8054
|
children: tabs.map((tab) => {
|
|
7942
8055
|
const isActive = tab.id === activeTabId;
|
|
8056
|
+
const isDraggingThis = tab.id === draggingId;
|
|
8057
|
+
const isDropTarget = dropTargetId === tab.id;
|
|
7943
8058
|
return /* @__PURE__ */ jsxs(
|
|
7944
8059
|
"div",
|
|
7945
8060
|
{
|
|
@@ -7947,15 +8062,23 @@ function MultiTabBar(props) {
|
|
|
7947
8062
|
if (el) tabRefs.current.set(tab.id, el);
|
|
7948
8063
|
else tabRefs.current.delete(tab.id);
|
|
7949
8064
|
},
|
|
8065
|
+
draggable: !!onTabsReorder,
|
|
7950
8066
|
onClick: () => {
|
|
7951
|
-
if (hasDragged.current) return;
|
|
7952
8067
|
if (!isActive) onTabClick(tab.id);
|
|
7953
8068
|
},
|
|
8069
|
+
onDragStart: (e) => handleDragStart(e, tab.id),
|
|
8070
|
+
onDragOver: (e) => handleDragOver(e, tab.id),
|
|
8071
|
+
onDrop: (e) => handleDrop(e, tab.id),
|
|
8072
|
+
onDragEnd: handleDragEnd,
|
|
7954
8073
|
className: `
|
|
7955
8074
|
group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
|
|
7956
|
-
${s.rounded} border border-b-0
|
|
8075
|
+
${s.rounded} border border-b-0 select-none
|
|
7957
8076
|
transition-colors duration-100
|
|
7958
8077
|
${isActive ? s.activeTab : s.inactiveTab}
|
|
8078
|
+
${onTabsReorder ? "cursor-grab" : "cursor-pointer"}
|
|
8079
|
+
${isDraggingThis ? "opacity-40" : ""}
|
|
8080
|
+
${isDropTarget && dropSide === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""}
|
|
8081
|
+
${isDropTarget && dropSide === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}
|
|
7959
8082
|
`,
|
|
7960
8083
|
children: [
|
|
7961
8084
|
isActive && /* @__PURE__ */ jsx(
|
|
@@ -7995,7 +8118,7 @@ function MultiTabBar(props) {
|
|
|
7995
8118
|
})
|
|
7996
8119
|
}
|
|
7997
8120
|
),
|
|
7998
|
-
|
|
8121
|
+
showPlus && /* @__PURE__ */ jsx(
|
|
7999
8122
|
"div",
|
|
8000
8123
|
{
|
|
8001
8124
|
className: `flex-shrink-0 flex items-center justify-center ${s.plusBtnArea}`,
|
|
@@ -8992,6 +9115,7 @@ function Sidebar(props) {
|
|
|
8992
9115
|
footer,
|
|
8993
9116
|
className,
|
|
8994
9117
|
showCollapseButton = false,
|
|
9118
|
+
collapseButtonPlacement = "right",
|
|
8995
9119
|
variant = "light",
|
|
8996
9120
|
primaryColor
|
|
8997
9121
|
} = props;
|
|
@@ -9078,7 +9202,7 @@ function Sidebar(props) {
|
|
|
9078
9202
|
"button",
|
|
9079
9203
|
{
|
|
9080
9204
|
onClick: () => setIsCollapsed((prev) => !prev),
|
|
9081
|
-
className: `absolute top-4
|
|
9205
|
+
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
9206
|
children: isCollapsed ? /* @__PURE__ */ jsx(PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsx(PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
|
|
9083
9207
|
}
|
|
9084
9208
|
),
|
|
@@ -9498,7 +9622,9 @@ function DetailModalFrame(props) {
|
|
|
9498
9622
|
renderExtraContent,
|
|
9499
9623
|
renderFooterExtra,
|
|
9500
9624
|
onDirtyChange,
|
|
9501
|
-
headerType
|
|
9625
|
+
headerType,
|
|
9626
|
+
headerIconVariant,
|
|
9627
|
+
headerIconSize
|
|
9502
9628
|
} = props;
|
|
9503
9629
|
const controller = useDetailController({ mode, onModeChange });
|
|
9504
9630
|
useEffect(() => {
|
|
@@ -9542,7 +9668,9 @@ function DetailModalFrame(props) {
|
|
|
9542
9668
|
{
|
|
9543
9669
|
type: isEditMode ? "edit" : headerType,
|
|
9544
9670
|
title,
|
|
9545
|
-
onClose: handleClose
|
|
9671
|
+
onClose: handleClose,
|
|
9672
|
+
variant: headerIconVariant,
|
|
9673
|
+
size: headerIconSize
|
|
9546
9674
|
}
|
|
9547
9675
|
) : /* @__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
9676
|
/* @__PURE__ */ jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
|