@farmzone/fz-react-ui 1.1.6 → 1.1.7

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 CHANGED
@@ -8073,15 +8073,15 @@ var VARIANT_STYLES = {
8073
8073
  inactiveText: "font-normal",
8074
8074
  indicator: "bg-blue-500",
8075
8075
  closeBtn: "rounded hover:bg-gray-300/60",
8076
- closeBtnWH: "w-3.5 h-3.5",
8077
- closeBtnSize: 10,
8076
+ closeBtnWH: "w-4 h-4",
8077
+ closeBtnSize: 12,
8078
8078
  plusBtnArea: "border-l border-gray-100 bg-white",
8079
8079
  plusBtn: "text-gray-400 hover:text-gray-600 hover:bg-gray-100",
8080
8080
  fadeOpacity: 0.12,
8081
- tabPy: "py-1.5",
8082
- tabPx: "px-3",
8083
- tabTextSize: "text-xs",
8084
- scrollPadding: "px-3 pt-1.5",
8081
+ tabHeight: "h-[38px]",
8082
+ tabPx: "px-4",
8083
+ tabTextSize: "text-sm",
8084
+ scrollPadding: "px-3 pt-2",
8085
8085
  rounded: "rounded-t-md"
8086
8086
  },
8087
8087
  dark: {
@@ -8092,15 +8092,15 @@ var VARIANT_STYLES = {
8092
8092
  inactiveText: "font-normal",
8093
8093
  indicator: "bg-indigo-400",
8094
8094
  closeBtn: "rounded hover:bg-gray-600/60",
8095
- closeBtnWH: "w-3.5 h-3.5",
8096
- closeBtnSize: 10,
8095
+ closeBtnWH: "w-4 h-4",
8096
+ closeBtnSize: 12,
8097
8097
  plusBtnArea: "border-l border-gray-700 bg-gray-900",
8098
8098
  plusBtn: "text-gray-500 hover:text-gray-300 hover:bg-gray-700",
8099
8099
  fadeOpacity: 0.4,
8100
- tabPy: "py-1.5",
8101
- tabPx: "px-3",
8102
- tabTextSize: "text-xs",
8103
- scrollPadding: "px-3 pt-1.5",
8100
+ tabHeight: "h-[38px]",
8101
+ tabPx: "px-4",
8102
+ tabTextSize: "text-sm",
8103
+ scrollPadding: "px-3 pt-2",
8104
8104
  rounded: "rounded-t-md"
8105
8105
  },
8106
8106
  "system-light": {
@@ -8116,7 +8116,7 @@ var VARIANT_STYLES = {
8116
8116
  plusBtnArea: "border-l border-gray-300 bg-gray-200",
8117
8117
  plusBtn: "text-slate-400 hover:text-slate-600 hover:bg-gray-300",
8118
8118
  fadeOpacity: 0.15,
8119
- tabPy: "py-2.5",
8119
+ tabHeight: "h-[38px]",
8120
8120
  tabPx: "px-5",
8121
8121
  tabTextSize: "text-sm",
8122
8122
  scrollPadding: "px-3 pt-2",
@@ -8135,7 +8135,7 @@ var VARIANT_STYLES = {
8135
8135
  plusBtnArea: "border-l border-slate-700 bg-slate-900",
8136
8136
  plusBtn: "text-slate-400 hover:text-slate-200 hover:bg-slate-700",
8137
8137
  fadeOpacity: 0.45,
8138
- tabPy: "py-2.5",
8138
+ tabHeight: "h-[38px]",
8139
8139
  tabPx: "px-5",
8140
8140
  tabTextSize: "text-sm",
8141
8141
  scrollPadding: "px-4 pt-2",
@@ -8147,6 +8147,65 @@ function easedFade(dir, opacity) {
8147
8147
  const c = (t) => `rgba(0,0,0,${(opacity * t).toFixed(3)})`;
8148
8148
  return `linear-gradient(${dir}, ${c(1)} 0%, ${c(0.72)} 20%, ${c(0.38)} 45%, ${c(0.1)} 70%, transparent 100%)`;
8149
8149
  }
8150
+ var MENU_ITEM_CLASSNAME = "flex w-full cursor-pointer items-center gap-2 rounded-md border-none bg-transparent px-2 py-1.5 text-left text-[13px] whitespace-nowrap text-gray-900 hover:bg-gray-100";
8151
+ function TabIconMenu(props) {
8152
+ const { icon, items, label } = props;
8153
+ const [open, setOpen] = React6.useState(false);
8154
+ if (items.length === 0) {
8155
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4.5 w-4.5 items-center justify-center", children: icon });
8156
+ }
8157
+ const showMore = (base) => open ? "flex" : base;
8158
+ return /* @__PURE__ */ jsxRuntime.jsx(
8159
+ SimplePopover,
8160
+ {
8161
+ open,
8162
+ onOpenChange: setOpen,
8163
+ align: "start",
8164
+ contentClassName: "w-auto min-w-28 p-1",
8165
+ trigger: /* @__PURE__ */ jsxRuntime.jsxs(
8166
+ "button",
8167
+ {
8168
+ type: "button",
8169
+ "aria-label": `${label} \uBA54\uB274`,
8170
+ className: "group/tab-menu relative flex h-4.5 w-4.5 cursor-pointer items-center justify-center rounded border-none bg-transparent p-0",
8171
+ children: [
8172
+ icon != null && /* @__PURE__ */ jsxRuntime.jsx(
8173
+ "span",
8174
+ {
8175
+ className: `flex items-center justify-center ${open ? "invisible" : "group-hover/tab-menu:invisible"}`,
8176
+ children: icon
8177
+ }
8178
+ ),
8179
+ /* @__PURE__ */ jsxRuntime.jsx(
8180
+ "span",
8181
+ {
8182
+ className: `absolute inset-0 items-center justify-center rounded bg-gray-200 text-gray-700 ${icon != null ? showMore("hidden group-hover/tab-menu:flex") : "flex"}`,
8183
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { size: 14 })
8184
+ }
8185
+ )
8186
+ ]
8187
+ }
8188
+ ),
8189
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
8190
+ "button",
8191
+ {
8192
+ type: "button",
8193
+ onClick: () => {
8194
+ setOpen(false);
8195
+ item.onSelect();
8196
+ },
8197
+ className: MENU_ITEM_CLASSNAME,
8198
+ style: item.selected ? { backgroundColor: "#F3F4F6" } : void 0,
8199
+ children: [
8200
+ item.icon != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center text-gray-500", children: item.icon }),
8201
+ item.label
8202
+ ]
8203
+ },
8204
+ item.key
8205
+ ))
8206
+ }
8207
+ );
8208
+ }
8150
8209
  function clusterTabs(tabs, getTabGroup) {
8151
8210
  const clusters = [];
8152
8211
  const clusterByGroupKey = /* @__PURE__ */ new Map();
@@ -8214,8 +8273,13 @@ function MultiTabPill(props) {
8214
8273
  draggable = false,
8215
8274
  onPointerDown,
8216
8275
  dropIndicator = null,
8217
- isDraggingThis = false
8276
+ isDraggingThis = false,
8277
+ icon,
8278
+ menuItems,
8279
+ groupColor
8218
8280
  } = props;
8281
+ const hasPrefix = icon != null || (menuItems?.length ?? 0) > 0;
8282
+ const outlinedByGroup = isActive && !!groupColor;
8219
8283
  return /* @__PURE__ */ jsxRuntime.jsxs(
8220
8284
  "div",
8221
8285
  {
@@ -8225,7 +8289,7 @@ function MultiTabPill(props) {
8225
8289
  if (!isActive) onClick();
8226
8290
  },
8227
8291
  className: `
8228
- group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
8292
+ group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabHeight} flex-shrink-0
8229
8293
  ${s.rounded} border border-b-0 select-none
8230
8294
  transition-colors duration-100
8231
8295
  ${isActive ? s.activeTab : s.inactiveTab}
@@ -8233,7 +8297,9 @@ function MultiTabPill(props) {
8233
8297
  ${isDraggingThis ? "opacity-40" : ""}
8234
8298
  ${dropIndicator === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""}
8235
8299
  ${dropIndicator === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}
8300
+ ${outlinedByGroup ? "z-[2]" : ""}
8236
8301
  `,
8302
+ style: outlinedByGroup ? { borderColor: groupColor } : void 0,
8237
8303
  children: [
8238
8304
  isActive && /* @__PURE__ */ jsxRuntime.jsx(
8239
8305
  "div",
@@ -8242,6 +8308,15 @@ function MultiTabPill(props) {
8242
8308
  style: accentColor ? { backgroundColor: accentColor } : void 0
8243
8309
  }
8244
8310
  ),
8311
+ hasPrefix && /* @__PURE__ */ jsxRuntime.jsx(
8312
+ "span",
8313
+ {
8314
+ className: "flex flex-shrink-0 items-center",
8315
+ onPointerDown: (e) => e.stopPropagation(),
8316
+ onClick: (e) => e.stopPropagation(),
8317
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabIconMenu, { icon, items: menuItems ?? [], label: tab.label })
8318
+ }
8319
+ ),
8245
8320
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${s.tabTextSize} max-w-35 truncate leading-none ${isActive ? s.activeText : s.inactiveText}`, children: tab.label }),
8246
8321
  showClose && /* @__PURE__ */ jsxRuntime.jsx(
8247
8322
  "button",
@@ -8273,7 +8348,9 @@ function MultiTabBar(props) {
8273
8348
  onTabsReorder,
8274
8349
  variant = "light",
8275
8350
  primaryColor,
8276
- getTabGroup
8351
+ getTabGroup,
8352
+ getTabIcon,
8353
+ getTabMenuItems
8277
8354
  } = props;
8278
8355
  const s = VARIANT_STYLES[variant];
8279
8356
  const scrollRef = React6.useRef(null);
@@ -8536,9 +8613,9 @@ function MultiTabBar(props) {
8536
8613
  const draggingGroupColor = draggingGroupKey ? groupColors.get(draggingGroupKey) : void 0;
8537
8614
  const ghost = draggingGroupKey && draggingGroupCluster?.group ? {
8538
8615
  label: draggingGroupCluster.group.label,
8539
- bg: (draggingGroupColor ?? TAB_PALETTE[0]).bg,
8540
- border: (draggingGroupColor ?? TAB_PALETTE[0]).border,
8541
- color: (draggingGroupColor ?? TAB_PALETTE[0]).base
8616
+ bg: (draggingGroupColor ?? TAB_PALETTE[0]).base,
8617
+ border: (draggingGroupColor ?? TAB_PALETTE[0]).base,
8618
+ color: "white"
8542
8619
  } : draggingTab ? { label: draggingTab.label, bg: "white", border: draggingColor ?? "#e5e7eb", color: "#111827" } : null;
8543
8620
  if (tabs.length === 0) return null;
8544
8621
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -8589,7 +8666,9 @@ function MultiTabBar(props) {
8589
8666
  draggable: reorderEnabled,
8590
8667
  isDraggingThis: tab.id === draggingId,
8591
8668
  dropIndicator: isDropTarget ? dropSide : isGroupDropTarget2 ? groupDropSide : null,
8592
- onPointerDown: (e) => handlePointerDown(e, tab.id)
8669
+ onPointerDown: (e) => handlePointerDown(e, tab.id),
8670
+ icon: getTabIcon?.(tab),
8671
+ menuItems: getTabMenuItems?.(tab)
8593
8672
  },
8594
8673
  tab.id
8595
8674
  );
@@ -8598,76 +8677,76 @@ function MultiTabBar(props) {
8598
8677
  const { key, label } = cluster.group;
8599
8678
  const color = groupColors.get(key) ?? TAB_PALETTE[0];
8600
8679
  const collapsed = collapsedGroups.has(key);
8601
- const groupHasActiveTab = cluster.tabs.some((t) => t.id === activeTabId);
8602
8680
  const isGroupDropTarget = groupDropTargetKey === `group:${key}`;
8603
8681
  const isDraggingThisGroup = draggingGroupKey === key;
8604
8682
  return /* @__PURE__ */ jsxRuntime.jsxs(
8605
8683
  "div",
8606
8684
  {
8607
8685
  ref: (el) => registerGroupRef(key, el),
8608
- className: "flex shrink-0 flex-col items-stretch",
8686
+ className: `relative flex shrink-0 items-end gap-0.5 ${isDraggingThisGroup ? "opacity-40" : ""} ${isGroupDropTarget && groupDropSide === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""} ${isGroupDropTarget && groupDropSide === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}`,
8609
8687
  children: [
8610
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
8611
- /* @__PURE__ */ jsxRuntime.jsxs(
8612
- "button",
8688
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex ${s.tabHeight} shrink-0 items-center px-1`, children: /* @__PURE__ */ jsxRuntime.jsxs(
8689
+ "button",
8690
+ {
8691
+ type: "button",
8692
+ onClick: () => {
8693
+ if (suppressClickRef.current) return;
8694
+ toggleGroupCollapsed(key);
8695
+ },
8696
+ onPointerDown: reorderEnabled ? (e) => handleGroupPointerDown(e, key) : void 0,
8697
+ "aria-expanded": !collapsed,
8698
+ title: collapsed ? "\uD558\uC704 \uD0ED \uD3BC\uCE58\uAE30" : "\uD558\uC704 \uD0ED \uC811\uAE30",
8699
+ className: `flex h-6.5 items-center gap-1 rounded-lg px-2.5 text-sm font-semibold whitespace-nowrap text-white select-none ${reorderEnabled ? isDraggingThisGroup ? "cursor-grabbing" : "cursor-grab" : "cursor-pointer"}`,
8700
+ style: { backgroundColor: color.base },
8701
+ children: [
8702
+ collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 14 }),
8703
+ label,
8704
+ canClose && /* @__PURE__ */ jsxRuntime.jsx(
8705
+ lucideReact.X,
8706
+ {
8707
+ size: 14,
8708
+ onClick: (e) => {
8709
+ e.stopPropagation();
8710
+ cluster.tabs.forEach((t) => onTabClose(t.id));
8711
+ }
8712
+ }
8713
+ )
8714
+ ]
8715
+ }
8716
+ ) }),
8717
+ !collapsed && cluster.tabs.map((tab) => {
8718
+ const isDropTarget = dropTargetId === tab.id;
8719
+ const isTabGroupDropTarget = groupDropTargetKey === `tab:${tab.id}`;
8720
+ return /* @__PURE__ */ jsxRuntime.jsx(
8721
+ MultiTabPill,
8613
8722
  {
8614
- type: "button",
8723
+ tab,
8724
+ isActive: tab.id === activeTabId,
8725
+ showClose: canClose,
8726
+ accentColor: color.base,
8727
+ style: s,
8615
8728
  onClick: () => {
8616
8729
  if (suppressClickRef.current) return;
8617
- toggleGroupCollapsed(key);
8618
- },
8619
- onPointerDown: reorderEnabled ? (e) => handleGroupPointerDown(e, key) : void 0,
8620
- "aria-expanded": !collapsed,
8621
- title: collapsed ? "\uD558\uC704 \uD0ED \uD3BC\uCE58\uAE30" : "\uD558\uC704 \uD0ED \uC811\uAE30",
8622
- className: `flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs font-bold whitespace-nowrap select-none ${reorderEnabled ? isDraggingThisGroup ? "cursor-grabbing" : "cursor-grab" : "cursor-pointer"} ${isDraggingThisGroup ? "opacity-40" : ""} ${isGroupDropTarget && groupDropSide === "before" ? "[box-shadow:inset_2px_0_0_0_#3b82f6]" : ""} ${isGroupDropTarget && groupDropSide === "after" ? "[box-shadow:inset_-2px_0_0_0_#3b82f6]" : ""}`,
8623
- style: { backgroundColor: color.bg, borderColor: color.border, color: color.base },
8624
- children: [
8625
- collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 12 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 12 }),
8626
- label,
8627
- canClose && /* @__PURE__ */ jsxRuntime.jsx(
8628
- lucideReact.X,
8629
- {
8630
- size: 12,
8631
- onClick: (e) => {
8632
- e.stopPropagation();
8633
- cluster.tabs.forEach((t) => onTabClose(t.id));
8634
- }
8635
- }
8636
- )
8637
- ]
8638
- }
8639
- ),
8640
- !collapsed && cluster.tabs.map((tab) => {
8641
- const isDropTarget = dropTargetId === tab.id;
8642
- const isTabGroupDropTarget = groupDropTargetKey === `tab:${tab.id}`;
8643
- return /* @__PURE__ */ jsxRuntime.jsx(
8644
- MultiTabPill,
8645
- {
8646
- tab,
8647
- isActive: tab.id === activeTabId,
8648
- showClose: canClose,
8649
- accentColor: color.base,
8650
- style: s,
8651
- onClick: () => {
8652
- if (suppressClickRef.current) return;
8653
- onTabClick(tab.id);
8654
- },
8655
- onClose: () => onTabClose(tab.id),
8656
- registerRef: registerTabRef,
8657
- draggable: reorderEnabled,
8658
- isDraggingThis: tab.id === draggingId,
8659
- dropIndicator: isDropTarget ? dropSide : isTabGroupDropTarget ? groupDropSide : null,
8660
- onPointerDown: (e) => handlePointerDown(e, tab.id)
8730
+ onTabClick(tab.id);
8661
8731
  },
8662
- tab.id
8663
- );
8664
- })
8665
- ] }),
8666
- /* @__PURE__ */ jsxRuntime.jsx(
8732
+ onClose: () => onTabClose(tab.id),
8733
+ registerRef: registerTabRef,
8734
+ draggable: reorderEnabled,
8735
+ isDraggingThis: tab.id === draggingId,
8736
+ dropIndicator: isDropTarget ? dropSide : isTabGroupDropTarget ? groupDropSide : null,
8737
+ onPointerDown: (e) => handlePointerDown(e, tab.id),
8738
+ icon: getTabIcon?.(tab),
8739
+ menuItems: getTabMenuItems?.(tab),
8740
+ groupColor: color.base
8741
+ },
8742
+ tab.id
8743
+ );
8744
+ }),
8745
+ !collapsed && /* @__PURE__ */ jsxRuntime.jsx(
8667
8746
  "div",
8668
8747
  {
8669
- className: "mt-1 h-0.75 rounded-full",
8670
- style: { backgroundColor: color.base, opacity: groupHasActiveTab ? 1 : 0.35 }
8748
+ className: "pointer-events-none absolute right-0 bottom-0 left-1 z-[1] h-0.5 rounded-l-full",
8749
+ style: { backgroundColor: color.base }
8671
8750
  }
8672
8751
  )
8673
8752
  ]
@@ -8693,7 +8772,9 @@ function MultiTabBar(props) {
8693
8772
  draggable: reorderEnabled,
8694
8773
  isDraggingThis: tab.id === draggingId,
8695
8774
  dropIndicator: isDropTarget ? dropSide : null,
8696
- onPointerDown: (e) => handlePointerDown(e, tab.id)
8775
+ onPointerDown: (e) => handlePointerDown(e, tab.id),
8776
+ icon: getTabIcon?.(tab),
8777
+ menuItems: getTabMenuItems?.(tab)
8697
8778
  },
8698
8779
  tab.id
8699
8780
  );
@@ -8721,7 +8802,7 @@ function MultiTabBar(props) {
8721
8802
  /* @__PURE__ */ jsxRuntime.jsx(
8722
8803
  "div",
8723
8804
  {
8724
- className: "pointer-events-none fixed z-50 flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-bold whitespace-nowrap shadow-lg",
8805
+ className: "pointer-events-none fixed z-50 flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-bold whitespace-nowrap shadow-lg",
8725
8806
  style: {
8726
8807
  left: dragPos.x + 12,
8727
8808
  top: dragPos.y + 12,