@farmzone/fz-react-ui 1.0.2 → 1.0.3

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.js CHANGED
@@ -208,6 +208,32 @@ function TooltipContent({
208
208
  }
209
209
  ) });
210
210
  }
211
+
212
+ // src/config/zIndex.ts
213
+ var Z_INDEX = {
214
+ TABLE_COL_STICKY: 1,
215
+ TABLE_FIXED_CELL: 5,
216
+ TABLE_FIXED_HEADER_CELL: 10,
217
+ LOCAL_OVERLAY: 10,
218
+ LAYOUT_HEADER: 20,
219
+ DROPDOWN_LOCAL: 20,
220
+ SIDEBAR_CONTAINER: 30,
221
+ SIDEBAR_BACKDROP: 40,
222
+ SIDEBAR: 50,
223
+ DROPDOWN: 50,
224
+ CALENDAR_ANCHORED: 50,
225
+ LOADING_OVERLAY_DEFAULT: 50,
226
+ DRAWING_CANVAS_1: 51,
227
+ DRAWING_CANVAS_2: 52,
228
+ DRAWING: 53,
229
+ MODAL_OVERLAY: 54,
230
+ MODAL: 55,
231
+ CALENDAR_PORTAL: 60,
232
+ TOOLTIP: 70,
233
+ SELECT_CONTENT: 100,
234
+ TOP: 9999,
235
+ MODAL_Z_STEP: 10
236
+ };
211
237
  function Tooltip2(props) {
212
238
  const {
213
239
  children,
@@ -219,6 +245,7 @@ function Tooltip2(props) {
219
245
  arrowClassName = "",
220
246
  contentClassName = "",
221
247
  contentStyle = {},
248
+ containerStyle,
222
249
  offsetX = 0,
223
250
  offsetY = 2,
224
251
  delayDuration = 0,
@@ -238,7 +265,9 @@ function Tooltip2(props) {
238
265
  sideOffset,
239
266
  collisionPadding: 8,
240
267
  style: {
241
- transform: `translateX(${offsetX}px) translateY(${translateY}px)`
268
+ zIndex: Z_INDEX.TOOLTIP,
269
+ transform: `translateX(${offsetX}px) translateY(${translateY}px)`,
270
+ ...containerStyle
242
271
  },
243
272
  children: /* @__PURE__ */ jsx("div", { className: "px-3 py-[5px] break-words whitespace-normal", style: contentStyle, children: /* @__PURE__ */ jsxs("p", { className: contentClassName, children: [
244
273
  content && /* @__PURE__ */ jsx("span", { children: content }),
@@ -1285,31 +1314,6 @@ function Spinner(props) {
1285
1314
  }
1286
1315
  );
1287
1316
  }
1288
-
1289
- // src/config/zIndex.ts
1290
- var Z_INDEX = {
1291
- TABLE_COL_STICKY: 1,
1292
- TABLE_FIXED_CELL: 5,
1293
- TABLE_FIXED_HEADER_CELL: 10,
1294
- LOCAL_OVERLAY: 10,
1295
- LAYOUT_HEADER: 20,
1296
- DROPDOWN_LOCAL: 20,
1297
- SIDEBAR_CONTAINER: 30,
1298
- SIDEBAR_BACKDROP: 40,
1299
- SIDEBAR: 50,
1300
- DROPDOWN: 50,
1301
- CALENDAR_ANCHORED: 50,
1302
- LOADING_OVERLAY_DEFAULT: 50,
1303
- DRAWING_CANVAS_1: 51,
1304
- DRAWING_CANVAS_2: 52,
1305
- DRAWING: 53,
1306
- MODAL_OVERLAY: 54,
1307
- MODAL: 55,
1308
- CALENDAR_PORTAL: 60,
1309
- SELECT_CONTENT: 100,
1310
- TOP: 9999,
1311
- MODAL_Z_STEP: 10
1312
- };
1313
1317
  function LoadingOverlay(props) {
1314
1318
  const {
1315
1319
  isVisible,
@@ -1924,13 +1928,18 @@ function ToastProvider() {
1924
1928
  }
1925
1929
 
1926
1930
  // src/components/DatePicker/config/utils.ts
1931
+ function makeLocalDate(year, monthIndex, day) {
1932
+ const d = /* @__PURE__ */ new Date(0);
1933
+ d.setFullYear(year, monthIndex, day);
1934
+ return d;
1935
+ }
1927
1936
  function parseLocalYmd(ymd) {
1928
1937
  const m = ymd.trim().match(/^(\d{4})-(\d{2})-(\d{2})$/);
1929
1938
  if (!m) return null;
1930
1939
  const y = Number(m[1]);
1931
1940
  const mo = Number(m[2]) - 1;
1932
1941
  const d = Number(m[3]);
1933
- const dt = new Date(y, mo, d);
1942
+ const dt = makeLocalDate(y, mo, d);
1934
1943
  if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== d) return null;
1935
1944
  return dt;
1936
1945
  }
@@ -1964,7 +1973,7 @@ function isCalendarDayAfterMax(date, maxYmd) {
1964
1973
  return ax > bx;
1965
1974
  }
1966
1975
  function formatDate(date) {
1967
- const year = date.getFullYear();
1976
+ const year = String(date.getFullYear()).padStart(4, "0");
1968
1977
  const month = String(date.getMonth() + 1).padStart(2, "0");
1969
1978
  const day = String(date.getDate()).padStart(2, "0");
1970
1979
  return `${year}-${month}-${day}`;
@@ -1983,7 +1992,6 @@ function validateAndFormatInput(input) {
1983
1992
  if (numbers.length === 0) return "";
1984
1993
  const clampYear = (raw) => {
1985
1994
  const n = parseInt(raw, 10);
1986
- if (n < 1) return "0001";
1987
1995
  if (n > 9999) return "9999";
1988
1996
  return raw;
1989
1997
  };
@@ -2006,7 +2014,7 @@ function validateAndFormatInput(input) {
2006
2014
  let day = dayRaw;
2007
2015
  if (day.length === 2) {
2008
2016
  const dayNum = parseInt(day, 10);
2009
- const lastDayOfMonth = new Date(parseInt(year, 10), parseInt(month, 10), 0).getDate();
2017
+ const lastDayOfMonth = makeLocalDate(parseInt(year, 10), parseInt(month, 10), 0).getDate();
2010
2018
  if (dayNum < 1) day = "01";
2011
2019
  else if (dayNum > lastDayOfMonth) day = lastDayOfMonth.toString().padStart(2, "0");
2012
2020
  }
@@ -2014,7 +2022,7 @@ function validateAndFormatInput(input) {
2014
2022
  }
2015
2023
 
2016
2024
  // src/components/DatePicker/calendar/config/default.ts
2017
- var DEFAULT_CALENDAR_YEAR_HALF_SPAN = 25;
2025
+ var DEFAULT_CALENDAR_YEAR_HALF_SPAN = 50;
2018
2026
  var CALENDAR_WEEKDAY_LABELS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
2019
2027
  var CALENDAR_RANGE_HINT = {
2020
2028
  start: "\uC2DC\uC791 \uB0A0\uC9DC\uB97C \uC120\uD0DD\uD558\uC138\uC694",
@@ -2038,7 +2046,7 @@ function parseYmdDateString(value) {
2038
2046
  return parseLocalYmd(value);
2039
2047
  }
2040
2048
  function resolveCalendarYearBounds(anchorYear, calendarYearRange) {
2041
- const fallbackMin = anchorYear - DEFAULT_CALENDAR_YEAR_HALF_SPAN;
2049
+ const fallbackMin = Math.max(0, anchorYear - DEFAULT_CALENDAR_YEAR_HALF_SPAN);
2042
2050
  const fallbackMax = anchorYear + DEFAULT_CALENDAR_YEAR_HALF_SPAN;
2043
2051
  const rawMin = calendarYearRange?.minYear?.trim();
2044
2052
  const rawMax = calendarYearRange?.maxYear?.trim();
@@ -2050,7 +2058,7 @@ function resolveCalendarYearBounds(anchorYear, calendarYearRange) {
2050
2058
  if (Number.isNaN(minParsed) || Number.isNaN(maxParsed) || minParsed > maxParsed) {
2051
2059
  return { minYear: fallbackMin, maxYear: fallbackMax };
2052
2060
  }
2053
- return { minYear: minParsed, maxYear: maxParsed };
2061
+ return { minYear: Math.max(0, minParsed), maxYear: maxParsed };
2054
2062
  }
2055
2063
  function buildCalendarYearSelectOptions(maxDate, anchorYear = (/* @__PURE__ */ new Date()).getFullYear(), calendarYearRange) {
2056
2064
  const { minYear, maxYear } = resolveCalendarYearBounds(anchorYear, calendarYearRange);
@@ -2059,7 +2067,7 @@ function buildCalendarYearSelectOptions(maxDate, anchorYear = (/* @__PURE__ */ n
2059
2067
  for (let y = maxYear; y >= minYear; y--) {
2060
2068
  options.push({
2061
2069
  value: String(y),
2062
- label: `${y}\uB144`,
2070
+ label: `${String(y).padStart(4, "0")}\uB144`,
2063
2071
  disabled: maxSelectableYear !== null && y > maxSelectableYear
2064
2072
  });
2065
2073
  }
@@ -2081,8 +2089,8 @@ function buildCalendarMonthSelectOptions(viewYear, maxDate) {
2081
2089
  return options;
2082
2090
  }
2083
2091
  function getCalendarMonthGrid(year, monthIndex) {
2084
- const firstDay = new Date(year, monthIndex, 1);
2085
- const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
2092
+ const firstDay = makeLocalDate(year, monthIndex, 1);
2093
+ const daysInMonth = makeLocalDate(year, monthIndex + 1, 0).getDate();
2086
2094
  const leadingEmpty = firstDay.getDay();
2087
2095
  const totalCells = leadingEmpty + daysInMonth;
2088
2096
  const trailingEmpty = totalCells % 7 === 0 ? 0 : 7 - totalCells % 7;
@@ -2090,7 +2098,7 @@ function getCalendarMonthGrid(year, monthIndex) {
2090
2098
  }
2091
2099
  function disableNextCalendarMonth(year, monthIndex, maxDate) {
2092
2100
  if (maxDate === void 0) return false;
2093
- return isCalendarDayAfterMax(new Date(year, monthIndex + 1, 1), maxDate);
2101
+ return isCalendarDayAfterMax(makeLocalDate(year, monthIndex + 1, 1), maxDate);
2094
2102
  }
2095
2103
  function scrollOpenYearSelectCheckedIntoView() {
2096
2104
  requestAnimationFrame(() => {
@@ -2136,7 +2144,7 @@ function RenderCalendar(props) {
2136
2144
  } = props;
2137
2145
  const year = currentDate.getFullYear();
2138
2146
  const monthIndex = currentDate.getMonth();
2139
- const anchorYear = (/* @__PURE__ */ new Date()).getFullYear();
2147
+ const anchorYear = year;
2140
2148
  const disableNextMonth = disableNextCalendarMonth(year, monthIndex, maxDate);
2141
2149
  const { leadingEmpty, daysInMonth, trailingEmpty } = getCalendarMonthGrid(year, monthIndex);
2142
2150
  const yearOptions = buildCalendarYearSelectOptions(maxDate, anchorYear, calendarYearRange);
@@ -2150,7 +2158,7 @@ function RenderCalendar(props) {
2150
2158
  days.push(/* @__PURE__ */ jsx("div", { className: "size-8", "aria-hidden": true }, `lead-${i}`));
2151
2159
  }
2152
2160
  for (let d = 1; d <= daysInMonth; d++) {
2153
- const date = new Date(year, monthIndex, d);
2161
+ const date = makeLocalDate(year, monthIndex, d);
2154
2162
  const dateFormatted = formatDate(date);
2155
2163
  const isToday = dateFormatted === todayFormatted;
2156
2164
  const isSelected = dateFormatted === selectedSingleYmd;
@@ -2249,7 +2257,7 @@ function RenderCalendar(props) {
2249
2257
  ]
2250
2258
  }
2251
2259
  ) : /* @__PURE__ */ jsxs("h3", { className: "text-lg font-semibold", children: [
2252
- year,
2260
+ String(year).padStart(4, "0"),
2253
2261
  "\uB144 ",
2254
2262
  monthIndex + 1,
2255
2263
  "\uC6D4"
@@ -2330,16 +2338,16 @@ function useCalendarState(props) {
2330
2338
  setIsCalendarOpen(false);
2331
2339
  };
2332
2340
  const goToPreviousMonth = () => {
2333
- setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1));
2341
+ setCurrentDate(makeLocalDate(currentDate.getFullYear(), currentDate.getMonth() - 1, 1));
2334
2342
  };
2335
2343
  const goToNextMonth = () => {
2336
- setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1));
2344
+ setCurrentDate(makeLocalDate(currentDate.getFullYear(), currentDate.getMonth() + 1, 1));
2337
2345
  };
2338
2346
  const handleYearChange = (year) => {
2339
- setCurrentDate(new Date(year, currentDate.getMonth(), 1));
2347
+ setCurrentDate(makeLocalDate(year, currentDate.getMonth(), 1));
2340
2348
  };
2341
2349
  const handleMonthChange = (month) => {
2342
- setCurrentDate(new Date(currentDate.getFullYear(), month, 1));
2350
+ setCurrentDate(makeLocalDate(currentDate.getFullYear(), month, 1));
2343
2351
  };
2344
2352
  return {
2345
2353
  isCalendarOpen,
@@ -2466,6 +2474,7 @@ function DatePickerRange(props) {
2466
2474
  return;
2467
2475
  }
2468
2476
  onRangeChange?.(formatted, endInputValue);
2477
+ if (isCalendarOpen && calendarPosition === "start") navigateToDateValue(formatted);
2469
2478
  } else if (formatted.length === 0) {
2470
2479
  onRangeChange?.(formatted, endInputValue);
2471
2480
  }
@@ -2479,6 +2488,7 @@ function DatePickerRange(props) {
2479
2488
  return;
2480
2489
  }
2481
2490
  onRangeChange?.(startInputValue, formatted);
2491
+ if (isCalendarOpen && calendarPosition === "end") navigateToDateValue(formatted);
2482
2492
  } else if (formatted.length === 0) {
2483
2493
  onRangeChange?.(startInputValue, formatted);
2484
2494
  }
@@ -2653,6 +2663,7 @@ function DatePickerSingle(props) {
2653
2663
  autoDatePosition,
2654
2664
  containerRef,
2655
2665
  toggleCalendar,
2666
+ navigateToDateValue,
2656
2667
  closeCalendar,
2657
2668
  goToPreviousMonth,
2658
2669
  goToNextMonth,
@@ -2670,7 +2681,7 @@ function DatePickerSingle(props) {
2670
2681
  const dateMatch = formatted.match(/^(\d{4})-(\d{2})-(\d{2})$/);
2671
2682
  if (dateMatch) {
2672
2683
  const [, year, month, day] = dateMatch;
2673
- const date = new Date(
2684
+ const date = makeLocalDate(
2674
2685
  Number.parseInt(year, 10),
2675
2686
  Number.parseInt(month, 10) - 1,
2676
2687
  Number.parseInt(day, 10)
@@ -2682,6 +2693,7 @@ function DatePickerSingle(props) {
2682
2693
  return;
2683
2694
  }
2684
2695
  onChange?.(formatted);
2696
+ if (isCalendarOpen) navigateToDateValue(formatted);
2685
2697
  }
2686
2698
  }
2687
2699
  } else {
@@ -3618,9 +3630,10 @@ function ConfirmModal(props) {
3618
3630
  ] }),
3619
3631
  /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center justify-end gap-2", children: [
3620
3632
  !isHideOkButton && /* @__PURE__ */ jsx(
3621
- Button,
3633
+ DebouncedButton,
3622
3634
  {
3623
3635
  ref: okButtonRef,
3636
+ debounceDelay: 500,
3624
3637
  variant: "outline",
3625
3638
  onClick: handleOkClick,
3626
3639
  className: "focus-visible:ring-2 focus-visible:ring-blue-400 focus-visible:ring-offset-1",
@@ -7610,7 +7623,17 @@ function PageFilter(props) {
7610
7623
  const rowGap2 = index !== 0 ? option.label ? gap : 5 : 0;
7611
7624
  switch (option.type) {
7612
7625
  case "input":
7613
- return /* @__PURE__ */ jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsx(Input2, { placeholder: option.placeholder, value: currentValue, onChange: handleInputChange(optionKey) }) }, String(optionKey));
7626
+ return /* @__PURE__ */ jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsx(
7627
+ Input2,
7628
+ {
7629
+ placeholder: option.placeholder,
7630
+ value: currentValue,
7631
+ onChange: handleInputChange(optionKey),
7632
+ onKeyDown: (e) => {
7633
+ if (e.key === "Enter") handleSubmit();
7634
+ }
7635
+ }
7636
+ ) }, String(optionKey));
7614
7637
  case "select":
7615
7638
  return /* @__PURE__ */ jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsx(
7616
7639
  Select2,
@@ -7684,9 +7707,84 @@ function PageFilter(props) {
7684
7707
  }
7685
7708
  );
7686
7709
  }
7710
+ var VARIANT_STYLES = {
7711
+ light: {
7712
+ container: "bg-white border-b border-gray-200",
7713
+ activeTab: "bg-gray-50 border-gray-200 text-gray-800 shadow-sm",
7714
+ inactiveTab: "bg-white border-gray-100 text-gray-400 hover:text-gray-600 hover:border-gray-200 hover:bg-gray-50",
7715
+ activeText: "font-semibold text-gray-800",
7716
+ inactiveText: "font-normal",
7717
+ indicator: "bg-blue-500",
7718
+ closeBtn: "hover:bg-gray-300/60",
7719
+ plusBtnArea: "border-l border-gray-100 bg-white",
7720
+ plusBtn: "text-gray-400 hover:text-gray-600 hover:bg-gray-100",
7721
+ fadeOpacity: 0.12,
7722
+ tabPy: "py-1.5",
7723
+ tabPx: "px-3",
7724
+ tabTextSize: "text-xs",
7725
+ scrollPadding: "px-3 pt-1.5",
7726
+ rounded: "rounded-t-md"
7727
+ },
7728
+ dark: {
7729
+ container: "bg-gray-900 border-b border-gray-700",
7730
+ activeTab: "bg-gray-800 border-gray-600 text-white shadow-sm",
7731
+ inactiveTab: "bg-gray-900 border-gray-700/50 text-gray-500 hover:text-gray-300 hover:border-gray-600 hover:bg-gray-800",
7732
+ activeText: "font-semibold text-white",
7733
+ inactiveText: "font-normal",
7734
+ indicator: "bg-indigo-400",
7735
+ closeBtn: "hover:bg-gray-600/60",
7736
+ plusBtnArea: "border-l border-gray-700 bg-gray-900",
7737
+ plusBtn: "text-gray-500 hover:text-gray-300 hover:bg-gray-700",
7738
+ fadeOpacity: 0.4,
7739
+ tabPy: "py-1.5",
7740
+ tabPx: "px-3",
7741
+ tabTextSize: "text-xs",
7742
+ scrollPadding: "px-3 pt-1.5",
7743
+ rounded: "rounded-t-md"
7744
+ },
7745
+ "system-light": {
7746
+ container: "bg-gray-200 border-b border-gray-300",
7747
+ activeTab: "bg-white border-gray-300 text-slate-800 shadow-sm",
7748
+ inactiveTab: "bg-transparent border-gray-300/80 text-slate-500 hover:text-slate-700 hover:bg-gray-200 hover:border-gray-300",
7749
+ activeText: "font-semibold text-slate-800",
7750
+ inactiveText: "font-medium",
7751
+ indicator: "bg-[#2b2b2b]",
7752
+ closeBtn: "hover:bg-gray-300",
7753
+ plusBtnArea: "border-l border-gray-300 bg-gray-200",
7754
+ plusBtn: "text-slate-400 hover:text-slate-600 hover:bg-gray-300",
7755
+ fadeOpacity: 0.15,
7756
+ tabPy: "py-2.5",
7757
+ tabPx: "px-5",
7758
+ tabTextSize: "text-sm",
7759
+ scrollPadding: "px-3 pt-2",
7760
+ rounded: "rounded-t-none"
7761
+ },
7762
+ "system-dark": {
7763
+ container: "bg-slate-900 border-b border-slate-700",
7764
+ activeTab: "bg-slate-800 border-slate-600 text-slate-100 shadow-sm",
7765
+ inactiveTab: "bg-transparent border-slate-700/50 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 hover:border-slate-700",
7766
+ activeText: "font-semibold text-slate-100",
7767
+ inactiveText: "font-medium",
7768
+ indicator: "bg-indigo-400",
7769
+ closeBtn: "hover:bg-slate-600/60",
7770
+ plusBtnArea: "border-l border-slate-700 bg-slate-900",
7771
+ plusBtn: "text-slate-400 hover:text-slate-200 hover:bg-slate-700",
7772
+ fadeOpacity: 0.45,
7773
+ tabPy: "py-2.5",
7774
+ tabPx: "px-5",
7775
+ tabTextSize: "text-sm",
7776
+ scrollPadding: "px-4 pt-2",
7777
+ rounded: "rounded-t-none"
7778
+ }
7779
+ };
7687
7780
  var PLUS_BTN_WIDTH = 36;
7781
+ function easedFade(dir, opacity) {
7782
+ const c = (t) => `rgba(0,0,0,${(opacity * t).toFixed(3)})`;
7783
+ return `linear-gradient(${dir}, ${c(1)} 0%, ${c(0.72)} 20%, ${c(0.38)} 45%, ${c(0.1)} 70%, transparent 100%)`;
7784
+ }
7688
7785
  function MultiTabBar(props) {
7689
- const { tabs, activeTabId, onTabClick, onTabClose, onTabAdd } = props;
7786
+ const { tabs, activeTabId, onTabClick, onTabClose, onTabAdd, variant = "light", primaryColor } = props;
7787
+ const s = VARIANT_STYLES[variant];
7690
7788
  const scrollRef = useRef(null);
7691
7789
  const tabRefs = useRef(/* @__PURE__ */ new Map());
7692
7790
  const [showLeftFade, setShowLeftFade] = useState(false);
@@ -7739,13 +7837,23 @@ function MultiTabBar(props) {
7739
7837
  const handleStopDrag = () => {
7740
7838
  isDragging.current = false;
7741
7839
  };
7840
+ useEffect(() => {
7841
+ const el = scrollRef.current;
7842
+ if (!el) return;
7843
+ const onWheel = (e) => {
7844
+ e.preventDefault();
7845
+ el.scrollLeft += e.deltaY || e.deltaX;
7846
+ };
7847
+ el.addEventListener("wheel", onWheel, { passive: false });
7848
+ return () => el.removeEventListener("wheel", onWheel);
7849
+ }, []);
7742
7850
  if (tabs.length === 0) return null;
7743
- return /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-full overflow-hidden bg-white border-b border-gray-200", children: /* @__PURE__ */ jsxs("div", { className: "relative flex items-stretch", children: [
7851
+ return /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 w-full overflow-hidden ${s.container}`, children: /* @__PURE__ */ jsxs("div", { className: "relative flex items-stretch", children: [
7744
7852
  showLeftFade && /* @__PURE__ */ jsx(
7745
7853
  "div",
7746
7854
  {
7747
7855
  className: "absolute left-0 top-0 bottom-0 w-10 pointer-events-none z-10",
7748
- style: { background: "linear-gradient(to right, white 30%, transparent)" }
7856
+ style: { background: easedFade("to right", s.fadeOpacity) }
7749
7857
  }
7750
7858
  ),
7751
7859
  showRightFade && /* @__PURE__ */ jsx(
@@ -7754,7 +7862,7 @@ function MultiTabBar(props) {
7754
7862
  className: "absolute top-0 bottom-0 w-10 pointer-events-none z-10",
7755
7863
  style: {
7756
7864
  right: PLUS_BTN_WIDTH,
7757
- background: "linear-gradient(to left, white 30%, transparent)"
7865
+ background: easedFade("to left", s.fadeOpacity)
7758
7866
  }
7759
7867
  }
7760
7868
  ),
@@ -7762,7 +7870,7 @@ function MultiTabBar(props) {
7762
7870
  "div",
7763
7871
  {
7764
7872
  ref: scrollRef,
7765
- className: "flex-1 min-w-0 flex items-end gap-0.5 px-3 pt-1.5 overflow-x-auto [&::-webkit-scrollbar]:hidden",
7873
+ className: `flex-1 min-w-0 flex items-end gap-0.5 ${s.scrollPadding} overflow-x-auto [&::-webkit-scrollbar]:hidden`,
7766
7874
  style: { scrollbarWidth: "none" },
7767
7875
  onScroll: updateFades,
7768
7876
  onMouseDown: handleMouseDown,
@@ -7783,17 +7891,23 @@ function MultiTabBar(props) {
7783
7891
  if (!isActive) onTabClick(tab.id);
7784
7892
  },
7785
7893
  className: `
7786
- group relative flex items-center gap-1.5 px-3 py-1.5 flex-shrink-0
7787
- rounded-t-md border border-b-0 cursor-pointer select-none
7894
+ group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
7895
+ ${s.rounded} border border-b-0 cursor-pointer select-none
7788
7896
  transition-colors duration-100
7789
- ${isActive ? "bg-gray-50 border-gray-200 text-gray-800 shadow-sm" : "bg-white border-gray-100 text-gray-400 hover:text-gray-600 hover:border-gray-200 hover:bg-gray-50"}
7897
+ ${isActive ? s.activeTab : s.inactiveTab}
7790
7898
  `,
7791
7899
  children: [
7792
- isActive && /* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 h-0.5 rounded-t-md bg-blue-500" }),
7900
+ isActive && /* @__PURE__ */ jsx(
7901
+ "div",
7902
+ {
7903
+ className: `absolute top-0 left-0 right-0 h-0.5 ${s.rounded} ${s.indicator}`,
7904
+ style: primaryColor ? { backgroundColor: primaryColor } : void 0
7905
+ }
7906
+ ),
7793
7907
  /* @__PURE__ */ jsx(
7794
7908
  "span",
7795
7909
  {
7796
- className: `text-xs max-w-35 truncate leading-none ${isActive ? "font-semibold text-gray-800" : "font-normal"}`,
7910
+ className: `${s.tabTextSize} max-w-35 truncate leading-none ${isActive ? s.activeText : s.inactiveText}`,
7797
7911
  children: tab.label
7798
7912
  }
7799
7913
  ),
@@ -7806,7 +7920,8 @@ function MultiTabBar(props) {
7806
7920
  },
7807
7921
  className: `
7808
7922
  flex-shrink-0 w-3.5 h-3.5 flex items-center justify-center
7809
- rounded hover:bg-gray-300/60 transition-all duration-100 cursor-pointer
7923
+ rounded transition-all duration-100 cursor-pointer
7924
+ ${s.closeBtn}
7810
7925
  ${isActive ? "opacity-100" : "opacity-40 group-hover:opacity-60"}
7811
7926
  `,
7812
7927
  children: /* @__PURE__ */ jsx(X, { size: 10, strokeWidth: 2.5 })
@@ -7822,14 +7937,14 @@ function MultiTabBar(props) {
7822
7937
  onTabAdd && /* @__PURE__ */ jsx(
7823
7938
  "div",
7824
7939
  {
7825
- className: "flex-shrink-0 flex items-center justify-center border-l border-gray-100 bg-white",
7940
+ className: `flex-shrink-0 flex items-center justify-center ${s.plusBtnArea}`,
7826
7941
  style: { width: PLUS_BTN_WIDTH },
7827
7942
  children: /* @__PURE__ */ jsx(
7828
7943
  "button",
7829
7944
  {
7830
7945
  onClick: onTabAdd,
7831
7946
  title: "\uD604\uC7AC \uD398\uC774\uC9C0\uB97C \uC0C8 \uD0ED\uC73C\uB85C \uC5F4\uAE30",
7832
- className: "w-6 h-6 flex items-center justify-center rounded text-gray-400 cursor-pointer hover:text-gray-600 hover:bg-gray-100 transition-colors",
7947
+ className: `w-6 h-6 flex items-center justify-center rounded cursor-pointer transition-colors ${s.plusBtn}`,
7833
7948
  children: /* @__PURE__ */ jsx(Plus, { size: 13, strokeWidth: 2 })
7834
7949
  }
7835
7950
  )
@@ -8614,19 +8729,212 @@ function FileUploader(props) {
8614
8729
  /* @__PURE__ */ jsx(FilePreviewViewer, { ...viewer.viewerProps, fileTypes, fileNames: files.map((f) => f.name) })
8615
8730
  ] });
8616
8731
  }
8732
+ var VARIANT_STYLES2 = {
8733
+ light: {
8734
+ aside: "bg-white border-r border-gray-200",
8735
+ sectionTitle: "text-xs font-semibold text-gray-500 tracking-wider mb-3",
8736
+ itemActive: "bg-blue-50 text-blue-600",
8737
+ itemInactive: "text-gray-700 hover:bg-gray-100",
8738
+ subItemActive: "text-blue-600 font-medium",
8739
+ subItemInactive: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
8740
+ childGroupBorder: "border-gray-100",
8741
+ childActive: "bg-blue-50 text-blue-600 font-medium",
8742
+ childInactive: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
8743
+ grandchildActive: "bg-blue-50 text-blue-600 font-medium",
8744
+ grandchildInactive: "text-gray-500 hover:bg-gray-50 hover:text-gray-900",
8745
+ collapseBtn: "bg-gray-50 hover:bg-gray-100",
8746
+ collapseIcon: "var(--color-sub-darkgray)",
8747
+ rounded: "rounded-lg",
8748
+ itemPy: "py-2",
8749
+ childPy: "py-1.5",
8750
+ grandchildPy: "py-1",
8751
+ itemFont: "font-semibold",
8752
+ itemTextSize: "text-sm",
8753
+ grandchildTextSize: "text-xs",
8754
+ iconClass: "w-4 h-4 flex-shrink-0",
8755
+ activeItemStyle: {},
8756
+ activeChildStyle: {},
8757
+ activeGrandchildStyle: {}
8758
+ },
8759
+ dark: {
8760
+ aside: "bg-gray-900 border-r border-gray-700",
8761
+ sectionTitle: "text-xs font-semibold text-gray-400 tracking-wider mb-3",
8762
+ itemActive: "bg-gray-700 text-white",
8763
+ itemInactive: "text-gray-300 hover:bg-gray-800",
8764
+ subItemActive: "text-blue-400 font-medium",
8765
+ subItemInactive: "text-gray-400 hover:bg-gray-800 hover:text-gray-100",
8766
+ childGroupBorder: "border-gray-700",
8767
+ childActive: "bg-gray-700 text-white font-medium",
8768
+ childInactive: "text-gray-400 hover:bg-gray-800 hover:text-gray-100",
8769
+ grandchildActive: "bg-gray-700 text-blue-400 font-medium",
8770
+ grandchildInactive: "text-gray-500 hover:bg-gray-800 hover:text-gray-100",
8771
+ collapseBtn: "bg-gray-800 hover:bg-gray-700",
8772
+ collapseIcon: "#9ca3af",
8773
+ rounded: "rounded-lg",
8774
+ itemPy: "py-2",
8775
+ childPy: "py-1.5",
8776
+ grandchildPy: "py-1",
8777
+ itemFont: "font-semibold",
8778
+ itemTextSize: "text-sm",
8779
+ grandchildTextSize: "text-xs",
8780
+ iconClass: "w-4 h-4 flex-shrink-0",
8781
+ activeItemStyle: {},
8782
+ activeChildStyle: {},
8783
+ activeGrandchildStyle: {}
8784
+ },
8785
+ "system-dark": {
8786
+ aside: "bg-slate-900 border-r border-slate-700",
8787
+ sectionTitle: "text-[10px] font-bold text-slate-500 uppercase tracking-[0.12em] mb-2 pb-2 border-b border-slate-700/70",
8788
+ itemActive: "bg-slate-800 text-white",
8789
+ itemInactive: "text-slate-300 hover:bg-slate-800/60 hover:text-white",
8790
+ subItemActive: "text-slate-100 font-medium",
8791
+ subItemInactive: "text-slate-400 hover:bg-slate-800/50 hover:text-slate-200",
8792
+ childGroupBorder: "border-slate-700/60",
8793
+ childActive: "bg-slate-800/70 text-slate-100 font-medium",
8794
+ childInactive: "text-slate-400 hover:bg-slate-800/50 hover:text-slate-200",
8795
+ grandchildActive: "text-slate-100 font-medium",
8796
+ grandchildInactive: "text-slate-500 hover:bg-slate-800/50 hover:text-slate-200",
8797
+ collapseBtn: "bg-slate-800 hover:bg-slate-700",
8798
+ collapseIcon: "#94a3b8",
8799
+ rounded: "rounded-none",
8800
+ itemPy: "py-3",
8801
+ childPy: "py-[10px]",
8802
+ grandchildPy: "py-2",
8803
+ itemFont: "font-medium",
8804
+ itemTextSize: "text-sm",
8805
+ grandchildTextSize: "text-xs",
8806
+ iconClass: "w-4.5 h-4.5 flex-shrink-0",
8807
+ activeItemStyle: { borderLeft: "3px solid #818cf8", paddingLeft: "9px" },
8808
+ activeChildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "14px" },
8809
+ activeGrandchildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "10px" }
8810
+ },
8811
+ "system-light": {
8812
+ aside: "bg-gray-50 border-r border-gray-200",
8813
+ sectionTitle: "text-[10px] font-bold text-slate-400 uppercase tracking-[0.12em] mb-2 pb-2 border-b border-gray-200",
8814
+ itemActive: "font-medium",
8815
+ itemInactive: "text-slate-700 hover:bg-gray-100",
8816
+ subItemActive: "text-[#2b2b2b] font-medium",
8817
+ subItemInactive: "text-slate-500 hover:bg-gray-100 hover:text-slate-800",
8818
+ childGroupBorder: "border-gray-200",
8819
+ childActive: "font-medium",
8820
+ childInactive: "text-slate-500 hover:bg-gray-100 hover:text-slate-800",
8821
+ grandchildActive: "text-[#2b2b2b] font-medium",
8822
+ grandchildInactive: "text-slate-500 hover:bg-gray-100 hover:text-slate-800",
8823
+ collapseBtn: "bg-gray-100 hover:bg-gray-200",
8824
+ collapseIcon: "#64748b",
8825
+ rounded: "rounded-none",
8826
+ itemPy: "py-3",
8827
+ childPy: "py-[10px]",
8828
+ grandchildPy: "py-2",
8829
+ itemFont: "font-medium",
8830
+ itemTextSize: "text-[15px]",
8831
+ grandchildTextSize: "text-sm",
8832
+ iconClass: "w-4.5 h-4.5 flex-shrink-0",
8833
+ activeItemStyle: {
8834
+ color: "#2b2b2b",
8835
+ backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8836
+ borderLeft: "3px solid #2b2b2b",
8837
+ paddingLeft: "9px"
8838
+ },
8839
+ activeChildStyle: {
8840
+ color: "#2b2b2b",
8841
+ backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8842
+ borderLeft: "2px solid #2b2b2b",
8843
+ paddingLeft: "14px"
8844
+ },
8845
+ activeGrandchildStyle: {
8846
+ color: "#2b2b2b",
8847
+ backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8848
+ borderLeft: "2px solid #2b2b2b",
8849
+ paddingLeft: "10px"
8850
+ }
8851
+ }
8852
+ };
8853
+ function tintedStyle(color) {
8854
+ return {
8855
+ color,
8856
+ backgroundColor: `color-mix(in srgb, ${color} 12%, transparent)`
8857
+ };
8858
+ }
8859
+ function textStyle(color) {
8860
+ return { color };
8861
+ }
8862
+ function solidStyle(color) {
8863
+ return {
8864
+ backgroundColor: `color-mix(in srgb, ${color} 25%, transparent)`,
8865
+ color: "#ffffff",
8866
+ boxShadow: `inset 3px 0 0 ${color}`
8867
+ };
8868
+ }
8869
+ var ACCENT_APPLIERS = {
8870
+ light: {
8871
+ itemActive: tintedStyle,
8872
+ subItemActive: textStyle,
8873
+ childActive: tintedStyle,
8874
+ grandchildActive: textStyle
8875
+ },
8876
+ dark: {
8877
+ itemActive: textStyle,
8878
+ subItemActive: textStyle,
8879
+ childActive: textStyle,
8880
+ grandchildActive: textStyle
8881
+ },
8882
+ "system-dark": {
8883
+ itemActive: (c) => ({
8884
+ ...solidStyle(c),
8885
+ boxShadow: void 0,
8886
+ borderLeft: `3px solid ${c}`,
8887
+ paddingLeft: "9px"
8888
+ }),
8889
+ subItemActive: textStyle,
8890
+ childActive: (c) => ({
8891
+ ...solidStyle(c),
8892
+ boxShadow: void 0,
8893
+ borderLeft: `2px solid ${c}`,
8894
+ paddingLeft: "14px"
8895
+ }),
8896
+ grandchildActive: (c) => ({
8897
+ ...textStyle(c),
8898
+ borderLeft: `2px solid ${c}`,
8899
+ paddingLeft: "10px"
8900
+ })
8901
+ },
8902
+ "system-light": {
8903
+ itemActive: (c) => ({
8904
+ ...tintedStyle(c),
8905
+ borderLeft: `3px solid ${c}`,
8906
+ paddingLeft: "9px"
8907
+ }),
8908
+ subItemActive: textStyle,
8909
+ childActive: (c) => ({
8910
+ ...tintedStyle(c),
8911
+ borderLeft: `2px solid ${c}`,
8912
+ paddingLeft: "14px"
8913
+ }),
8914
+ grandchildActive: (c) => ({
8915
+ ...tintedStyle(c),
8916
+ borderLeft: `2px solid ${c}`,
8917
+ paddingLeft: "10px"
8918
+ })
8919
+ }
8920
+ };
8617
8921
  function Sidebar(props) {
8618
8922
  const navigate = useNavigate();
8619
- const { isOpen: isOpen2, onClose, menuSections, header, className, showCollapseButton = false } = props;
8923
+ const {
8924
+ onClose,
8925
+ menuSections,
8926
+ header,
8927
+ className,
8928
+ showCollapseButton = false,
8929
+ variant = "light",
8930
+ primaryColor
8931
+ } = props;
8620
8932
  const { pathname } = useLocation();
8621
8933
  const [isCollapsed, setIsCollapsed] = useState(false);
8622
- const [isContentVisible, setIsContentVisible] = useState(true);
8623
8934
  const [expandedItems, setExpandedItems] = useState(/* @__PURE__ */ new Set());
8624
8935
  const [expandedSubItems, setExpandedSubItems] = useState(/* @__PURE__ */ new Set());
8625
- useEffect(() => {
8626
- if (isCollapsed) return;
8627
- const timer = setTimeout(() => setIsContentVisible(true), 300);
8628
- return () => clearTimeout(timer);
8629
- }, [isCollapsed]);
8936
+ const s = VARIANT_STYLES2[variant];
8937
+ const applier = ACCENT_APPLIERS[variant];
8630
8938
  useEffect(() => {
8631
8939
  menuSections.forEach((section) => {
8632
8940
  section.items.forEach((item) => {
@@ -8677,167 +8985,178 @@ function Sidebar(props) {
8677
8985
  window.open(path, "_blank", "noopener,noreferrer");
8678
8986
  } else if (path !== "") {
8679
8987
  navigate(path);
8680
- onClose();
8988
+ onClose?.();
8681
8989
  }
8682
8990
  };
8683
- return /* @__PURE__ */ jsxs(Fragment, { children: [
8684
- isOpen2 && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/10 bg-opacity-50 z-40 lg:hidden", onClick: onClose }),
8685
- /* @__PURE__ */ jsxs(
8686
- "aside",
8687
- {
8688
- className: `
8689
- ${isCollapsed ? "w-11 min-w-11" : "min-w-60 w-62"}
8690
- ${isOpen2 ? "translate-x-0" : "-translate-x-full lg:translate-x-0"}
8691
- hide-scrollbar fixed lg:relative top-0 left-0 h-screen bg-white border-r border-gray-200 z-50 shrink-0 overflow-y-auto
8692
- transition-transform duration-300 ease-in-out
8693
- ${className ?? ""}
8694
- `,
8695
- children: [
8696
- showCollapseButton && /* @__PURE__ */ jsx(
8697
- "button",
8698
- {
8699
- onClick: () => {
8700
- if (!isCollapsed) setIsContentVisible(false);
8701
- setIsCollapsed((prev) => !prev);
8702
- },
8703
- className: "absolute top-4 right-2 z-20 w-6.5 h-6.5 bg-gray-50 rounded-full flex items-center justify-center hover:bg-gray-50 transition-colors cursor-pointer hover:bg-gray-100",
8704
- children: isCollapsed ? /* @__PURE__ */ jsx(PanelRightClose, { size: 18, color: "var(--color-sub-darkgray)" }) : /* @__PURE__ */ jsx(PanelLeftClose, { size: 18, color: "var(--color-sub-darkgray)" })
8705
- }
8706
- ),
8707
- isContentVisible && /* @__PURE__ */ jsxs("div", { className: "py-6 pl-6 pr-4", children: [
8708
- /* @__PURE__ */ jsx(
8709
- "button",
8710
- {
8711
- onClick: onClose,
8712
- className: "lg:hidden absolute top-4 right-4 p-2 hover:bg-gray-100 rounded-lg transition-colors text-2xl leading-none",
8713
- "aria-label": "Close menu",
8714
- children: "x"
8715
- }
8716
- ),
8717
- header && /* @__PURE__ */ jsx("div", { className: "mb-10 mt-2", children: header }),
8718
- /* @__PURE__ */ jsx("nav", { className: "space-y-6", children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
8719
- section.title && /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold text-gray-500 tracking-wider mb-3", children: section.title }),
8720
- /* @__PURE__ */ jsx("div", { className: "space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsxs("div", { children: [
8721
- /* @__PURE__ */ jsxs(
8722
- "button",
8723
- {
8724
- onClick: () => {
8725
- if (item.children) {
8726
- toggleExpand(item.label);
8727
- } else if (item.path) {
8728
- handleItemClick(item.path);
8729
- }
8730
- },
8731
- className: `
8732
- w-full text-left flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors
8733
- ${!item.children && pathname === item.path ? "bg-blue-50 text-blue-600" : "text-gray-700 hover:bg-gray-100"}
8734
- cursor-pointer
8735
- `,
8736
- children: [
8737
- /* @__PURE__ */ jsx(item.icon, { className: "w-4 h-4 flex-shrink-0" }),
8738
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
8739
- item.children && /* @__PURE__ */ jsx(
8740
- "svg",
8741
- {
8742
- className: `w-4 h-4 transition-transform ${expandedItems.has(item.label) ? "rotate-90" : ""}`,
8743
- fill: "none",
8744
- stroke: "currentColor",
8745
- viewBox: "0 0 24 24",
8746
- children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
8747
- }
8748
- ),
8749
- item.path?.includes("https") && /* @__PURE__ */ jsx(
8750
- "svg",
8751
- {
8752
- className: "w-4 h-4 flex-shrink-0 text-gray-400",
8753
- fill: "none",
8754
- stroke: "currentColor",
8755
- viewBox: "0 0 24 24",
8756
- children: /* @__PURE__ */ jsx(
8757
- "path",
8991
+ return /* @__PURE__ */ jsxs(
8992
+ "aside",
8993
+ {
8994
+ className: `
8995
+ ${isCollapsed ? "w-11 min-w-11" : "min-w-60 w-62"}
8996
+ transition-[width,min-width] duration-300 ease-in-out
8997
+ hide-scrollbar relative h-screen shrink-0 overflow-y-auto overflow-x-hidden
8998
+ ${s.aside}
8999
+ ${className ?? ""}
9000
+ `,
9001
+ children: [
9002
+ showCollapseButton && /* @__PURE__ */ jsx(
9003
+ "button",
9004
+ {
9005
+ onClick: () => setIsCollapsed((prev) => !prev),
9006
+ className: `absolute top-4 right-2 z-20 w-6.5 h-6.5 rounded-full flex items-center justify-center transition-colors cursor-pointer ${s.collapseBtn}`,
9007
+ children: isCollapsed ? /* @__PURE__ */ jsx(PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsx(PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
9008
+ }
9009
+ ),
9010
+ /* @__PURE__ */ jsxs(
9011
+ "div",
9012
+ {
9013
+ className: `transition-opacity duration-200 ease-in-out ${isCollapsed ? "opacity-0 pointer-events-none select-none" : "opacity-100"} ${variant === "system-dark" || variant === "system-light" ? "px-1 py-6" : "px-4 py-6"}`,
9014
+ style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9015
+ children: [
9016
+ header && /* @__PURE__ */ jsx("div", { className: "mb-6 mt-2", children: header }),
9017
+ /* @__PURE__ */ jsx("nav", { className: "space-y-6", children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
9018
+ section.title && /* @__PURE__ */ jsx("div", { className: s.sectionTitle, children: section.title }),
9019
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => {
9020
+ const isActive = !item.children && pathname === item.path;
9021
+ return /* @__PURE__ */ jsxs("div", { children: [
9022
+ /* @__PURE__ */ jsxs(
9023
+ "button",
9024
+ {
9025
+ onClick: () => {
9026
+ if (item.children) {
9027
+ toggleExpand(item.label);
9028
+ } else if (item.path) {
9029
+ handleItemClick(item.path);
9030
+ }
9031
+ },
9032
+ className: `
9033
+ w-full text-left flex items-center gap-2 px-3 ${s.itemPy} ${s.rounded} ${s.itemTextSize} ${s.itemFont} transition-colors cursor-pointer
9034
+ ${isActive ? s.itemActive : s.itemInactive}
9035
+ `,
9036
+ style: {
9037
+ ...isActive ? s.activeItemStyle : {},
9038
+ ...isActive && primaryColor ? applier.itemActive(primaryColor) : {}
9039
+ },
9040
+ children: [
9041
+ /* @__PURE__ */ jsx(item.icon, { className: s.iconClass }),
9042
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
9043
+ item.children && /* @__PURE__ */ jsx(
9044
+ "svg",
9045
+ {
9046
+ className: `w-4 h-4 transition-transform ${expandedItems.has(item.label) ? "rotate-90" : ""}`,
9047
+ fill: "none",
9048
+ stroke: "currentColor",
9049
+ viewBox: "0 0 24 24",
9050
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
9051
+ }
9052
+ ),
9053
+ item.path?.includes("https") && /* @__PURE__ */ jsx(
9054
+ "svg",
8758
9055
  {
8759
- strokeLinecap: "round",
8760
- strokeLinejoin: "round",
8761
- strokeWidth: 2,
8762
- d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
9056
+ className: "w-4 h-4 flex-shrink-0 opacity-50",
9057
+ fill: "none",
9058
+ stroke: "currentColor",
9059
+ viewBox: "0 0 24 24",
9060
+ children: /* @__PURE__ */ jsx(
9061
+ "path",
9062
+ {
9063
+ strokeLinecap: "round",
9064
+ strokeLinejoin: "round",
9065
+ strokeWidth: 2,
9066
+ d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
9067
+ }
9068
+ )
8763
9069
  }
8764
9070
  )
8765
- }
8766
- )
8767
- ]
8768
- }
8769
- ),
8770
- item.children && expandedItems.has(item.label) && /* @__PURE__ */ jsx("div", { className: "ml-[25px] mt-1 space-y-1", children: item.children.map((child, childIndex) => {
8771
- if (child.children && child.children.length > 0) {
8772
- const subKey = `${item.label}::${child.label}`;
8773
- const isSubExpanded = expandedSubItems.has(subKey);
8774
- const isSubActive = child.children.some((gc) => gc.path === pathname);
8775
- return /* @__PURE__ */ jsxs("div", { children: [
8776
- /* @__PURE__ */ jsxs(
8777
- "button",
8778
- {
8779
- onClick: () => toggleSubExpand(subKey),
8780
- className: `
8781
- w-full text-left flex items-center justify-between px-3 py-1.5 rounded-lg text-sm transition-colors cursor-pointer
8782
- ${isSubActive ? "text-blue-600 font-medium" : "text-gray-600 hover:bg-gray-50 hover:text-gray-900"}
8783
- `,
8784
- children: [
8785
- /* @__PURE__ */ jsx("span", { children: child.label }),
8786
- /* @__PURE__ */ jsx(
8787
- "svg",
8788
- {
8789
- className: `w-3 h-3 transition-transform ${isSubExpanded ? "rotate-90" : ""}`,
8790
- fill: "none",
8791
- stroke: "currentColor",
8792
- viewBox: "0 0 24 24",
8793
- children: /* @__PURE__ */ jsx(
8794
- "path",
9071
+ ]
9072
+ }
9073
+ ),
9074
+ item.children && expandedItems.has(item.label) && /* @__PURE__ */ jsx("div", { className: `ml-5 mt-0.5 space-y-0.5 border-l ${s.childGroupBorder}`, children: item.children.map((child, childIndex) => {
9075
+ if (child.children && child.children.length > 0) {
9076
+ const subKey = `${item.label}::${child.label}`;
9077
+ const isSubExpanded = expandedSubItems.has(subKey);
9078
+ const isSubActive = child.children.some((gc) => gc.path === pathname);
9079
+ return /* @__PURE__ */ jsxs("div", { children: [
9080
+ /* @__PURE__ */ jsxs(
9081
+ "button",
9082
+ {
9083
+ onClick: () => toggleSubExpand(subKey),
9084
+ className: `
9085
+ w-full text-left flex items-center justify-between pl-4 pr-3 ${s.childPy} ${s.rounded} ${s.itemTextSize} transition-colors cursor-pointer
9086
+ ${isSubActive ? s.subItemActive : s.subItemInactive}
9087
+ `,
9088
+ style: isSubActive && primaryColor ? applier.subItemActive(primaryColor) : void 0,
9089
+ children: [
9090
+ /* @__PURE__ */ jsx("span", { children: child.label }),
9091
+ /* @__PURE__ */ jsx(
9092
+ "svg",
8795
9093
  {
8796
- strokeLinecap: "round",
8797
- strokeLinejoin: "round",
8798
- strokeWidth: 2,
8799
- d: "M9 5l7 7-7 7"
9094
+ className: `w-3 h-3 transition-transform ${isSubExpanded ? "rotate-90" : ""}`,
9095
+ fill: "none",
9096
+ stroke: "currentColor",
9097
+ viewBox: "0 0 24 24",
9098
+ children: /* @__PURE__ */ jsx(
9099
+ "path",
9100
+ {
9101
+ strokeLinecap: "round",
9102
+ strokeLinejoin: "round",
9103
+ strokeWidth: 2,
9104
+ d: "M9 5l7 7-7 7"
9105
+ }
9106
+ )
8800
9107
  }
8801
9108
  )
8802
- }
8803
- )
8804
- ]
8805
- }
8806
- ),
8807
- isSubExpanded && /* @__PURE__ */ jsx("div", { className: "ml-3 mt-0.5 space-y-0.5 border-l border-gray-200 pl-2", children: child.children.map((grandchild) => /* @__PURE__ */ jsx(
9109
+ ]
9110
+ }
9111
+ ),
9112
+ isSubExpanded && /* @__PURE__ */ jsx("div", { className: "ml-3 mt-0.5 space-y-0.5 pl-2", children: child.children.map((grandchild) => {
9113
+ const isGrandchildActive = pathname === grandchild.path;
9114
+ return /* @__PURE__ */ jsx(
9115
+ "button",
9116
+ {
9117
+ onClick: () => handleItemClick(grandchild.path),
9118
+ className: `
9119
+ w-full text-left px-3 ${s.grandchildPy} ${s.rounded} ${s.grandchildTextSize} transition-colors cursor-pointer
9120
+ ${isGrandchildActive ? s.grandchildActive : s.grandchildInactive}
9121
+ `,
9122
+ style: {
9123
+ ...isGrandchildActive ? s.activeGrandchildStyle : {},
9124
+ ...isGrandchildActive && primaryColor ? applier.grandchildActive(primaryColor) : {}
9125
+ },
9126
+ children: grandchild.label
9127
+ },
9128
+ grandchild.path
9129
+ );
9130
+ }) })
9131
+ ] }, child.label);
9132
+ }
9133
+ const isChildActive = pathname === child.path;
9134
+ return /* @__PURE__ */ jsx(
8808
9135
  "button",
8809
9136
  {
8810
- onClick: () => handleItemClick(grandchild.path),
9137
+ onClick: () => handleItemClick(child.path ?? ""),
8811
9138
  className: `
8812
- w-full text-left px-3 py-1 rounded-lg text-sm transition-colors cursor-pointer
8813
- ${pathname === grandchild.path ? "text-blue-600 font-medium" : "text-gray-500 hover:bg-gray-50 hover:text-gray-900"}
8814
- `,
8815
- children: grandchild.label
9139
+ w-full text-left pl-4 pr-3 ${s.childPy} ${s.rounded} ${s.itemTextSize} transition-colors cursor-pointer
9140
+ ${isChildActive ? s.childActive : s.childInactive}
9141
+ `,
9142
+ style: {
9143
+ ...isChildActive ? s.activeChildStyle : {},
9144
+ ...isChildActive && primaryColor ? applier.childActive(primaryColor) : {}
9145
+ },
9146
+ children: child.label
8816
9147
  },
8817
- grandchild.path
8818
- )) })
8819
- ] }, child.label);
8820
- }
8821
- return /* @__PURE__ */ jsx(
8822
- "button",
8823
- {
8824
- onClick: () => handleItemClick(child.path ?? ""),
8825
- className: `
8826
- w-full text-left px-3 py-1.5 rounded-lg text-sm transition-colors cursor-pointer
8827
- ${pathname === child.path ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-600 hover:bg-gray-50 hover:text-gray-900"}
8828
- `,
8829
- children: child.label
8830
- },
8831
- childIndex
8832
- );
9148
+ childIndex
9149
+ );
9150
+ }) })
9151
+ ] }, item.label);
8833
9152
  }) })
8834
- ] }, item.label)) })
8835
- ] }, section.title ?? sectionIndex)) })
8836
- ] })
8837
- ]
8838
- }
8839
- )
8840
- ] });
9153
+ ] }, section.title ?? sectionIndex)) })
9154
+ ]
9155
+ }
9156
+ )
9157
+ ]
9158
+ }
9159
+ );
8841
9160
  }
8842
9161
  function useDetailController(params = {}) {
8843
9162
  const { mode: controlledMode, onModeChange } = params;
@@ -9134,10 +9453,7 @@ function DetailModalFrame(props) {
9134
9453
  const isEditMode = controller.mode === "edit";
9135
9454
  const canEdit = Boolean(editSchema && (editFields || renderEditBody));
9136
9455
  return /* @__PURE__ */ jsxs(Modal, { isOpen: open, onClose: handleClose, contentClassName: cn("max-w-2xl", contentClassName), children: [
9137
- /* @__PURE__ */ jsxs(ModalHeader, { className: "flex flex-row items-center justify-between", children: [
9138
- /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900", children: title }),
9139
- !isEditMode && canEdit && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleEdit, children: "\uC218\uC815" })
9140
- ] }),
9456
+ /* @__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 }) }),
9141
9457
  /* @__PURE__ */ jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
9142
9458
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx(
9143
9459
  DetailContent,
@@ -9157,8 +9473,9 @@ function DetailModalFrame(props) {
9157
9473
  ] }),
9158
9474
  /* @__PURE__ */ jsx(ModalFooter, { className: "flex justify-end gap-2", children: isEditMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
9159
9475
  /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleCancelEdit, disabled: controller.isSaving, children: "\uCDE8\uC18C" }),
9160
- /* @__PURE__ */ jsx(Button, { type: "submit", form: controller.formId, variant: "save", disabled: controller.isSaving, children: controller.isSaving ? "\uC800\uC7A5 \uC911..." : "\uC800\uC7A5" })
9476
+ /* @__PURE__ */ jsx(Button, { type: "submit", form: controller.formId, variant: "save", disabled: controller.isSaving, children: "\uC800\uC7A5" })
9161
9477
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
9478
+ canEdit && /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleEdit, children: "\uC218\uC815" }),
9162
9479
  renderFooterExtra,
9163
9480
  /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClose, children: "\uB2EB\uAE30" })
9164
9481
  ] }) })