@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.cjs
CHANGED
|
@@ -3478,36 +3478,100 @@ var MODAL_ICONS = {
|
|
|
3478
3478
|
delete: lucideReact.Trash2,
|
|
3479
3479
|
warning: lucideReact.TriangleAlert
|
|
3480
3480
|
};
|
|
3481
|
+
var VARIANT_CONFIG = {
|
|
3482
|
+
default: {
|
|
3483
|
+
container: "bg-gradient-to-r from-blue-50 to-indigo-50 border-blue-100",
|
|
3484
|
+
iconBg: "bg-blue-100 rounded-full",
|
|
3485
|
+
iconColor: "text-main",
|
|
3486
|
+
titleColor: "text-gray-900",
|
|
3487
|
+
descColor: "text-gray-500",
|
|
3488
|
+
closeBtn: "text-gray-400 group-hover:text-gray-600"
|
|
3489
|
+
},
|
|
3490
|
+
"system-light": {
|
|
3491
|
+
container: "bg-gray-50 border-gray-200",
|
|
3492
|
+
iconBg: "bg-white border border-gray-200 shadow-sm rounded-lg",
|
|
3493
|
+
iconColor: "text-slate-600",
|
|
3494
|
+
titleColor: "text-gray-900",
|
|
3495
|
+
descColor: "text-gray-500",
|
|
3496
|
+
closeBtn: "text-gray-400 group-hover:text-gray-600"
|
|
3497
|
+
},
|
|
3498
|
+
"system-dark": {
|
|
3499
|
+
container: "bg-slate-800 border-slate-700",
|
|
3500
|
+
iconBg: "bg-slate-700 border border-slate-600 shadow-sm rounded-lg",
|
|
3501
|
+
iconColor: "text-slate-300",
|
|
3502
|
+
titleColor: "text-slate-100",
|
|
3503
|
+
descColor: "text-slate-400",
|
|
3504
|
+
closeBtn: "text-slate-500 group-hover:text-slate-300"
|
|
3505
|
+
}
|
|
3506
|
+
};
|
|
3507
|
+
var SIZE_CONFIG = {
|
|
3508
|
+
md: {
|
|
3509
|
+
padding: "px-6 py-5",
|
|
3510
|
+
iconBox: "w-10 h-10",
|
|
3511
|
+
iconSize: 20,
|
|
3512
|
+
gap: "gap-3",
|
|
3513
|
+
titleSize: "text-xl font-bold",
|
|
3514
|
+
descSize: "text-sm mt-0.5",
|
|
3515
|
+
closeBtnBox: "w-10 h-10",
|
|
3516
|
+
closeIconSize: 20
|
|
3517
|
+
},
|
|
3518
|
+
sm: {
|
|
3519
|
+
padding: "px-4 py-4",
|
|
3520
|
+
iconBox: "w-8 h-8",
|
|
3521
|
+
iconSize: 16,
|
|
3522
|
+
gap: "gap-2.5",
|
|
3523
|
+
titleSize: "text-lg font-bold",
|
|
3524
|
+
descSize: "text-sm mt-0.5",
|
|
3525
|
+
closeBtnBox: "w-8 h-8",
|
|
3526
|
+
closeIconSize: 16
|
|
3527
|
+
}
|
|
3528
|
+
};
|
|
3481
3529
|
function ModalIconHeader(props) {
|
|
3482
|
-
const {
|
|
3530
|
+
const {
|
|
3531
|
+
type,
|
|
3532
|
+
title,
|
|
3533
|
+
description,
|
|
3534
|
+
onClose,
|
|
3535
|
+
action,
|
|
3536
|
+
variant = "default",
|
|
3537
|
+
size: size2 = "md",
|
|
3538
|
+
primaryColor,
|
|
3539
|
+
className
|
|
3540
|
+
} = props;
|
|
3483
3541
|
const Icon2 = MODAL_ICONS[type];
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
type: "button",
|
|
3503
|
-
onClick: onClose,
|
|
3504
|
-
className: "flex items-center justify-center w-10 h-10 rounded-full transition-colors group cursor-pointer hover:bg-black/5 shrink-0",
|
|
3505
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 20, className: "text-gray-400 group-hover:text-gray-600 transition-colors" })
|
|
3506
|
-
}
|
|
3507
|
-
)
|
|
3542
|
+
const v = VARIANT_CONFIG[variant];
|
|
3543
|
+
const s = SIZE_CONFIG[size2];
|
|
3544
|
+
const hasColor = !!primaryColor;
|
|
3545
|
+
const isDark = variant === "system-dark";
|
|
3546
|
+
const containerStyle = hasColor && variant === "default" ? {
|
|
3547
|
+
background: `linear-gradient(to right, color-mix(in srgb, ${primaryColor} 6%, white), color-mix(in srgb, ${primaryColor} 12%, white))`,
|
|
3548
|
+
borderColor: `color-mix(in srgb, ${primaryColor} 25%, transparent)`
|
|
3549
|
+
} : void 0;
|
|
3550
|
+
const iconBgStyle = hasColor ? {
|
|
3551
|
+
backgroundColor: isDark ? `color-mix(in srgb, ${primaryColor} 20%, #334155)` : `color-mix(in srgb, ${primaryColor} 15%, white)`
|
|
3552
|
+
} : void 0;
|
|
3553
|
+
const iconColorStyle = hasColor && !isDark ? { color: primaryColor } : void 0;
|
|
3554
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ModalHeader, { className: cn("p-0 text-left space-y-0", v.container, className), style: containerStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between", s.padding), children: [
|
|
3555
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center", s.gap), children: [
|
|
3556
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center justify-center shrink-0", s.iconBox, v.iconBg), style: iconBgStyle, children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { size: s.iconSize, className: hasColor && !isDark ? void 0 : v.iconColor, style: iconColorStyle }) }),
|
|
3557
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3558
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: cn(s.titleSize, v.titleColor), children: title }),
|
|
3559
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn(s.descSize, v.descColor), children: description })
|
|
3508
3560
|
] })
|
|
3509
|
-
}
|
|
3510
|
-
|
|
3561
|
+
] }),
|
|
3562
|
+
action ?? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3563
|
+
"button",
|
|
3564
|
+
{
|
|
3565
|
+
type: "button",
|
|
3566
|
+
onClick: onClose,
|
|
3567
|
+
className: cn(
|
|
3568
|
+
"flex items-center justify-center rounded-full transition-colors group cursor-pointer hover:bg-black/5 shrink-0",
|
|
3569
|
+
s.closeBtnBox
|
|
3570
|
+
),
|
|
3571
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: s.closeIconSize, className: cn("transition-colors", v.closeBtn) })
|
|
3572
|
+
}
|
|
3573
|
+
)
|
|
3574
|
+
] }) });
|
|
3511
3575
|
}
|
|
3512
3576
|
function Modal(props) {
|
|
3513
3577
|
const {
|
|
@@ -7727,7 +7791,7 @@ function PageFilter(props) {
|
|
|
7727
7791
|
onChange: handleSelectChange(optionKey),
|
|
7728
7792
|
options: option.options,
|
|
7729
7793
|
placeholder: "\uC120\uD0DD",
|
|
7730
|
-
canReset: true,
|
|
7794
|
+
canReset: option.canReset ?? true,
|
|
7731
7795
|
containerClassName: option.containerClassName ?? "w-30"
|
|
7732
7796
|
}
|
|
7733
7797
|
) }, String(optionKey));
|
|
@@ -7878,16 +7942,24 @@ function easedFade(dir, opacity) {
|
|
|
7878
7942
|
return `linear-gradient(${dir}, ${c(1)} 0%, ${c(0.72)} 20%, ${c(0.38)} 45%, ${c(0.1)} 70%, transparent 100%)`;
|
|
7879
7943
|
}
|
|
7880
7944
|
function MultiTabBar(props) {
|
|
7881
|
-
const {
|
|
7945
|
+
const {
|
|
7946
|
+
tabs,
|
|
7947
|
+
activeTabId,
|
|
7948
|
+
onTabClick,
|
|
7949
|
+
onTabClose,
|
|
7950
|
+
onTabAdd,
|
|
7951
|
+
onTabsReorder,
|
|
7952
|
+
variant = "light",
|
|
7953
|
+
primaryColor
|
|
7954
|
+
} = props;
|
|
7882
7955
|
const s = VARIANT_STYLES[variant];
|
|
7883
7956
|
const scrollRef = React6.useRef(null);
|
|
7884
7957
|
const tabRefs = React6.useRef(/* @__PURE__ */ new Map());
|
|
7885
7958
|
const [showLeftFade, setShowLeftFade] = React6.useState(false);
|
|
7886
7959
|
const [showRightFade, setShowRightFade] = React6.useState(false);
|
|
7887
|
-
const
|
|
7888
|
-
const
|
|
7889
|
-
const
|
|
7890
|
-
const dragScrollLeft = React6.useRef(0);
|
|
7960
|
+
const [draggingId, setDraggingId] = React6.useState(null);
|
|
7961
|
+
const [dropTargetId, setDropTargetId] = React6.useState(null);
|
|
7962
|
+
const [dropSide, setDropSide] = React6.useState("before");
|
|
7891
7963
|
React6.useEffect(() => {
|
|
7892
7964
|
if (!activeTabId || !scrollRef.current) return;
|
|
7893
7965
|
const el = tabRefs.current.get(activeTabId);
|
|
@@ -7915,23 +7987,6 @@ function MultiTabBar(props) {
|
|
|
7915
7987
|
if (scrollRef.current) obs.observe(scrollRef.current);
|
|
7916
7988
|
return () => obs.disconnect();
|
|
7917
7989
|
}, [tabs]);
|
|
7918
|
-
const handleMouseDown = (e) => {
|
|
7919
|
-
if (!scrollRef.current) return;
|
|
7920
|
-
isDragging.current = true;
|
|
7921
|
-
hasDragged.current = false;
|
|
7922
|
-
dragStartX.current = e.pageX - scrollRef.current.getBoundingClientRect().left;
|
|
7923
|
-
dragScrollLeft.current = scrollRef.current.scrollLeft;
|
|
7924
|
-
};
|
|
7925
|
-
const handleMouseMove = (e) => {
|
|
7926
|
-
if (!isDragging.current || !scrollRef.current) return;
|
|
7927
|
-
const x = e.pageX - scrollRef.current.getBoundingClientRect().left;
|
|
7928
|
-
const walk = x - dragStartX.current;
|
|
7929
|
-
if (Math.abs(walk) > 4) hasDragged.current = true;
|
|
7930
|
-
scrollRef.current.scrollLeft = dragScrollLeft.current - walk;
|
|
7931
|
-
};
|
|
7932
|
-
const handleStopDrag = () => {
|
|
7933
|
-
isDragging.current = false;
|
|
7934
|
-
};
|
|
7935
7990
|
React6.useEffect(() => {
|
|
7936
7991
|
const el = scrollRef.current;
|
|
7937
7992
|
if (!el) return;
|
|
@@ -7942,6 +7997,46 @@ function MultiTabBar(props) {
|
|
|
7942
7997
|
el.addEventListener("wheel", onWheel, { passive: false });
|
|
7943
7998
|
return () => el.removeEventListener("wheel", onWheel);
|
|
7944
7999
|
}, []);
|
|
8000
|
+
const handleDragStart = (e, tabId) => {
|
|
8001
|
+
setDraggingId(tabId);
|
|
8002
|
+
e.dataTransfer.effectAllowed = "move";
|
|
8003
|
+
};
|
|
8004
|
+
const handleDragOver = (e, tabId) => {
|
|
8005
|
+
e.preventDefault();
|
|
8006
|
+
if (tabId === draggingId) return;
|
|
8007
|
+
e.dataTransfer.dropEffect = "move";
|
|
8008
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
8009
|
+
setDropSide(e.clientX < rect.left + rect.width / 2 ? "before" : "after");
|
|
8010
|
+
setDropTargetId(tabId);
|
|
8011
|
+
};
|
|
8012
|
+
const handleDrop = (e, targetTabId) => {
|
|
8013
|
+
e.preventDefault();
|
|
8014
|
+
if (!draggingId || draggingId === targetTabId) {
|
|
8015
|
+
setDraggingId(null);
|
|
8016
|
+
setDropTargetId(null);
|
|
8017
|
+
return;
|
|
8018
|
+
}
|
|
8019
|
+
if (onTabsReorder) {
|
|
8020
|
+
const fromIdx = tabs.findIndex((t) => t.id === draggingId);
|
|
8021
|
+
if (fromIdx !== -1) {
|
|
8022
|
+
const newTabs = [...tabs];
|
|
8023
|
+
const moved = newTabs.splice(fromIdx, 1)[0];
|
|
8024
|
+
let insertIdx = newTabs.findIndex((t) => t.id === targetTabId);
|
|
8025
|
+
if (insertIdx !== -1) {
|
|
8026
|
+
if (dropSide === "after") insertIdx += 1;
|
|
8027
|
+
newTabs.splice(insertIdx, 0, moved);
|
|
8028
|
+
onTabsReorder(newTabs);
|
|
8029
|
+
}
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
setDraggingId(null);
|
|
8033
|
+
setDropTargetId(null);
|
|
8034
|
+
};
|
|
8035
|
+
const handleDragEnd = () => {
|
|
8036
|
+
setDraggingId(null);
|
|
8037
|
+
setDropTargetId(null);
|
|
8038
|
+
};
|
|
8039
|
+
const showPlus = !!onTabAdd;
|
|
7945
8040
|
if (tabs.length === 0) return null;
|
|
7946
8041
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 w-full overflow-hidden ${s.container}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-stretch", children: [
|
|
7947
8042
|
showLeftFade && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7956,7 +8051,7 @@ function MultiTabBar(props) {
|
|
|
7956
8051
|
{
|
|
7957
8052
|
className: "absolute top-0 bottom-0 w-10 pointer-events-none z-10",
|
|
7958
8053
|
style: {
|
|
7959
|
-
right: PLUS_BTN_WIDTH,
|
|
8054
|
+
right: showPlus ? PLUS_BTN_WIDTH : 0,
|
|
7960
8055
|
background: easedFade("to left", s.fadeOpacity)
|
|
7961
8056
|
}
|
|
7962
8057
|
}
|
|
@@ -7968,12 +8063,10 @@ function MultiTabBar(props) {
|
|
|
7968
8063
|
className: `flex-1 min-w-0 flex items-end gap-0.5 ${s.scrollPadding} overflow-x-auto [&::-webkit-scrollbar]:hidden`,
|
|
7969
8064
|
style: { scrollbarWidth: "none" },
|
|
7970
8065
|
onScroll: updateFades,
|
|
7971
|
-
onMouseDown: handleMouseDown,
|
|
7972
|
-
onMouseMove: handleMouseMove,
|
|
7973
|
-
onMouseUp: handleStopDrag,
|
|
7974
|
-
onMouseLeave: handleStopDrag,
|
|
7975
8066
|
children: tabs.map((tab) => {
|
|
7976
8067
|
const isActive = tab.id === activeTabId;
|
|
8068
|
+
const isDraggingThis = tab.id === draggingId;
|
|
8069
|
+
const isDropTarget = dropTargetId === tab.id;
|
|
7977
8070
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7978
8071
|
"div",
|
|
7979
8072
|
{
|
|
@@ -7981,15 +8074,23 @@ function MultiTabBar(props) {
|
|
|
7981
8074
|
if (el) tabRefs.current.set(tab.id, el);
|
|
7982
8075
|
else tabRefs.current.delete(tab.id);
|
|
7983
8076
|
},
|
|
8077
|
+
draggable: !!onTabsReorder,
|
|
7984
8078
|
onClick: () => {
|
|
7985
|
-
if (hasDragged.current) return;
|
|
7986
8079
|
if (!isActive) onTabClick(tab.id);
|
|
7987
8080
|
},
|
|
8081
|
+
onDragStart: (e) => handleDragStart(e, tab.id),
|
|
8082
|
+
onDragOver: (e) => handleDragOver(e, tab.id),
|
|
8083
|
+
onDrop: (e) => handleDrop(e, tab.id),
|
|
8084
|
+
onDragEnd: handleDragEnd,
|
|
7988
8085
|
className: `
|
|
7989
8086
|
group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
|
|
7990
|
-
${s.rounded} border border-b-0
|
|
8087
|
+
${s.rounded} border border-b-0 select-none
|
|
7991
8088
|
transition-colors duration-100
|
|
7992
8089
|
${isActive ? s.activeTab : s.inactiveTab}
|
|
8090
|
+
${onTabsReorder ? "cursor-grab" : "cursor-pointer"}
|
|
8091
|
+
${isDraggingThis ? "opacity-40" : ""}
|
|
8092
|
+
${isDropTarget && dropSide === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""}
|
|
8093
|
+
${isDropTarget && dropSide === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}
|
|
7993
8094
|
`,
|
|
7994
8095
|
children: [
|
|
7995
8096
|
isActive && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -8029,7 +8130,7 @@ function MultiTabBar(props) {
|
|
|
8029
8130
|
})
|
|
8030
8131
|
}
|
|
8031
8132
|
),
|
|
8032
|
-
|
|
8133
|
+
showPlus && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8033
8134
|
"div",
|
|
8034
8135
|
{
|
|
8035
8136
|
className: `flex-shrink-0 flex items-center justify-center ${s.plusBtnArea}`,
|
|
@@ -9026,6 +9127,7 @@ function Sidebar(props) {
|
|
|
9026
9127
|
footer,
|
|
9027
9128
|
className,
|
|
9028
9129
|
showCollapseButton = false,
|
|
9130
|
+
collapseButtonPlacement = "right",
|
|
9029
9131
|
variant = "light",
|
|
9030
9132
|
primaryColor
|
|
9031
9133
|
} = props;
|
|
@@ -9112,7 +9214,7 @@ function Sidebar(props) {
|
|
|
9112
9214
|
"button",
|
|
9113
9215
|
{
|
|
9114
9216
|
onClick: () => setIsCollapsed((prev) => !prev),
|
|
9115
|
-
className: `absolute top-4
|
|
9217
|
+
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"}`,
|
|
9116
9218
|
children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
|
|
9117
9219
|
}
|
|
9118
9220
|
),
|
|
@@ -9532,7 +9634,9 @@ function DetailModalFrame(props) {
|
|
|
9532
9634
|
renderExtraContent,
|
|
9533
9635
|
renderFooterExtra,
|
|
9534
9636
|
onDirtyChange,
|
|
9535
|
-
headerType
|
|
9637
|
+
headerType,
|
|
9638
|
+
headerIconVariant,
|
|
9639
|
+
headerIconSize
|
|
9536
9640
|
} = props;
|
|
9537
9641
|
const controller = useDetailController({ mode, onModeChange });
|
|
9538
9642
|
React6.useEffect(() => {
|
|
@@ -9576,7 +9680,9 @@ function DetailModalFrame(props) {
|
|
|
9576
9680
|
{
|
|
9577
9681
|
type: isEditMode ? "edit" : headerType,
|
|
9578
9682
|
title,
|
|
9579
|
-
onClose: handleClose
|
|
9683
|
+
onClose: handleClose,
|
|
9684
|
+
variant: headerIconVariant,
|
|
9685
|
+
size: headerIconSize
|
|
9580
9686
|
}
|
|
9581
9687
|
) : /* @__PURE__ */ jsxRuntime.jsx(ModalHeader, { className: "flex flex-row items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold text-gray-900", children: title }) }),
|
|
9582
9688
|
/* @__PURE__ */ jsxRuntime.jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
|