@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.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-[#ededed] border-gray-200",
|
|
3492
|
+
iconBg: "bg-white border border-gray-200 shadow-xs 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 {
|
|
@@ -7726,8 +7790,8 @@ function PageFilter(props) {
|
|
|
7726
7790
|
value: currentValue,
|
|
7727
7791
|
onChange: handleSelectChange(optionKey),
|
|
7728
7792
|
options: option.options,
|
|
7729
|
-
placeholder: "\uC120\uD0DD",
|
|
7730
|
-
canReset: true,
|
|
7793
|
+
placeholder: option.placeholder || "\uC120\uD0DD",
|
|
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,64 @@ 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
|
+
e.stopPropagation();
|
|
8015
|
+
if (!draggingId || draggingId === targetTabId) {
|
|
8016
|
+
setDraggingId(null);
|
|
8017
|
+
setDropTargetId(null);
|
|
8018
|
+
return;
|
|
8019
|
+
}
|
|
8020
|
+
if (onTabsReorder) {
|
|
8021
|
+
const fromIdx = tabs.findIndex((t) => t.id === draggingId);
|
|
8022
|
+
if (fromIdx !== -1) {
|
|
8023
|
+
const newTabs = [...tabs];
|
|
8024
|
+
const moved = newTabs.splice(fromIdx, 1)[0];
|
|
8025
|
+
let insertIdx = newTabs.findIndex((t) => t.id === targetTabId);
|
|
8026
|
+
if (insertIdx !== -1) {
|
|
8027
|
+
if (dropSide === "after") insertIdx += 1;
|
|
8028
|
+
newTabs.splice(insertIdx, 0, moved);
|
|
8029
|
+
onTabsReorder(newTabs);
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
}
|
|
8033
|
+
setDraggingId(null);
|
|
8034
|
+
setDropTargetId(null);
|
|
8035
|
+
};
|
|
8036
|
+
const handleContainerDrop = (e) => {
|
|
8037
|
+
e.preventDefault();
|
|
8038
|
+
if (!draggingId || !onTabsReorder) {
|
|
8039
|
+
setDraggingId(null);
|
|
8040
|
+
setDropTargetId(null);
|
|
8041
|
+
return;
|
|
8042
|
+
}
|
|
8043
|
+
const fromIdx = tabs.findIndex((t) => t.id === draggingId);
|
|
8044
|
+
if (fromIdx !== -1 && fromIdx < tabs.length - 1) {
|
|
8045
|
+
const newTabs = [...tabs];
|
|
8046
|
+
const moved = newTabs.splice(fromIdx, 1)[0];
|
|
8047
|
+
newTabs.push(moved);
|
|
8048
|
+
onTabsReorder(newTabs);
|
|
8049
|
+
}
|
|
8050
|
+
setDraggingId(null);
|
|
8051
|
+
setDropTargetId(null);
|
|
8052
|
+
};
|
|
8053
|
+
const handleDragEnd = () => {
|
|
8054
|
+
setDraggingId(null);
|
|
8055
|
+
setDropTargetId(null);
|
|
8056
|
+
};
|
|
8057
|
+
const showPlus = !!onTabAdd;
|
|
7945
8058
|
if (tabs.length === 0) return null;
|
|
7946
8059
|
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
8060
|
showLeftFade && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7956,7 +8069,7 @@ function MultiTabBar(props) {
|
|
|
7956
8069
|
{
|
|
7957
8070
|
className: "absolute top-0 bottom-0 w-10 pointer-events-none z-10",
|
|
7958
8071
|
style: {
|
|
7959
|
-
right: PLUS_BTN_WIDTH,
|
|
8072
|
+
right: showPlus ? PLUS_BTN_WIDTH : 0,
|
|
7960
8073
|
background: easedFade("to left", s.fadeOpacity)
|
|
7961
8074
|
}
|
|
7962
8075
|
}
|
|
@@ -7968,12 +8081,14 @@ function MultiTabBar(props) {
|
|
|
7968
8081
|
className: `flex-1 min-w-0 flex items-end gap-0.5 ${s.scrollPadding} overflow-x-auto [&::-webkit-scrollbar]:hidden`,
|
|
7969
8082
|
style: { scrollbarWidth: "none" },
|
|
7970
8083
|
onScroll: updateFades,
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
8084
|
+
onDragOver: (e) => {
|
|
8085
|
+
if (draggingId) e.preventDefault();
|
|
8086
|
+
},
|
|
8087
|
+
onDrop: handleContainerDrop,
|
|
7975
8088
|
children: tabs.map((tab) => {
|
|
7976
8089
|
const isActive = tab.id === activeTabId;
|
|
8090
|
+
const isDraggingThis = tab.id === draggingId;
|
|
8091
|
+
const isDropTarget = dropTargetId === tab.id;
|
|
7977
8092
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7978
8093
|
"div",
|
|
7979
8094
|
{
|
|
@@ -7981,15 +8096,23 @@ function MultiTabBar(props) {
|
|
|
7981
8096
|
if (el) tabRefs.current.set(tab.id, el);
|
|
7982
8097
|
else tabRefs.current.delete(tab.id);
|
|
7983
8098
|
},
|
|
8099
|
+
draggable: !!onTabsReorder,
|
|
7984
8100
|
onClick: () => {
|
|
7985
|
-
if (hasDragged.current) return;
|
|
7986
8101
|
if (!isActive) onTabClick(tab.id);
|
|
7987
8102
|
},
|
|
8103
|
+
onDragStart: (e) => handleDragStart(e, tab.id),
|
|
8104
|
+
onDragOver: (e) => handleDragOver(e, tab.id),
|
|
8105
|
+
onDrop: (e) => handleDrop(e, tab.id),
|
|
8106
|
+
onDragEnd: handleDragEnd,
|
|
7988
8107
|
className: `
|
|
7989
8108
|
group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
|
|
7990
|
-
${s.rounded} border border-b-0
|
|
8109
|
+
${s.rounded} border border-b-0 select-none
|
|
7991
8110
|
transition-colors duration-100
|
|
7992
8111
|
${isActive ? s.activeTab : s.inactiveTab}
|
|
8112
|
+
${onTabsReorder ? "cursor-grab" : "cursor-pointer"}
|
|
8113
|
+
${isDraggingThis ? "opacity-40" : ""}
|
|
8114
|
+
${isDropTarget && dropSide === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""}
|
|
8115
|
+
${isDropTarget && dropSide === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}
|
|
7993
8116
|
`,
|
|
7994
8117
|
children: [
|
|
7995
8118
|
isActive && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -8029,7 +8152,7 @@ function MultiTabBar(props) {
|
|
|
8029
8152
|
})
|
|
8030
8153
|
}
|
|
8031
8154
|
),
|
|
8032
|
-
|
|
8155
|
+
showPlus && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8033
8156
|
"div",
|
|
8034
8157
|
{
|
|
8035
8158
|
className: `flex-shrink-0 flex items-center justify-center ${s.plusBtnArea}`,
|
|
@@ -9026,6 +9149,7 @@ function Sidebar(props) {
|
|
|
9026
9149
|
footer,
|
|
9027
9150
|
className,
|
|
9028
9151
|
showCollapseButton = false,
|
|
9152
|
+
collapseButtonPlacement = "right",
|
|
9029
9153
|
variant = "light",
|
|
9030
9154
|
primaryColor
|
|
9031
9155
|
} = props;
|
|
@@ -9112,7 +9236,7 @@ function Sidebar(props) {
|
|
|
9112
9236
|
"button",
|
|
9113
9237
|
{
|
|
9114
9238
|
onClick: () => setIsCollapsed((prev) => !prev),
|
|
9115
|
-
className: `absolute top-4
|
|
9239
|
+
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
9240
|
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
9241
|
}
|
|
9118
9242
|
),
|
|
@@ -9532,7 +9656,9 @@ function DetailModalFrame(props) {
|
|
|
9532
9656
|
renderExtraContent,
|
|
9533
9657
|
renderFooterExtra,
|
|
9534
9658
|
onDirtyChange,
|
|
9535
|
-
headerType
|
|
9659
|
+
headerType,
|
|
9660
|
+
headerIconVariant,
|
|
9661
|
+
headerIconSize
|
|
9536
9662
|
} = props;
|
|
9537
9663
|
const controller = useDetailController({ mode, onModeChange });
|
|
9538
9664
|
React6.useEffect(() => {
|
|
@@ -9576,7 +9702,9 @@ function DetailModalFrame(props) {
|
|
|
9576
9702
|
{
|
|
9577
9703
|
type: isEditMode ? "edit" : headerType,
|
|
9578
9704
|
title,
|
|
9579
|
-
onClose: handleClose
|
|
9705
|
+
onClose: handleClose,
|
|
9706
|
+
variant: headerIconVariant,
|
|
9707
|
+
size: headerIconSize
|
|
9580
9708
|
}
|
|
9581
9709
|
) : /* @__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
9710
|
/* @__PURE__ */ jsxRuntime.jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
|