@farmzone/fz-react-ui 1.0.2 → 1.0.4

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
@@ -78,9 +78,10 @@ var buttonVariants = classVarianceAuthority.cva(
78
78
  delete: "bg-white border border-sub-red text-main-red hover:bg-red-50 disabled:bg-light-gray disabled:border-sub-lightgray-2 disabled:text-sub-lightgray-2 font-bold min-w-22",
79
79
  reset: "bg-white border border-sub-lightgray-2 text-sub-darkgray hover:bg-gray-100 hover:text-black",
80
80
  search: "bg-main-blue border-none text-white hover:bg-main-blue/90",
81
- file: "bg-sub-darkgray text-white hover:bg-sub-darkgray/80",
81
+ file: "bg-btn-file text-white hover:bg-btn-file/90",
82
82
  carousel: "bg-white border border-gray-300 hover:bg-gray-100 hover:text-black rounded-full",
83
83
  accent: "btn-grad text-white rounded-full",
84
+ metal: "btn-metal text-white min-w-22",
84
85
  ghost: "p-1 h-auto rounded-sm bg-transparent hover:bg-sub-lightgray text-sub-darkgray hover:bg-inherit",
85
86
  link: "bg-transparent border-none text-main-blue underline-offset-4 hover:underline h-auto p-0"
86
87
  },
@@ -242,6 +243,32 @@ function TooltipContent({
242
243
  }
243
244
  ) });
244
245
  }
246
+
247
+ // src/config/zIndex.ts
248
+ var Z_INDEX = {
249
+ TABLE_COL_STICKY: 1,
250
+ TABLE_FIXED_CELL: 5,
251
+ TABLE_FIXED_HEADER_CELL: 10,
252
+ LOCAL_OVERLAY: 10,
253
+ LAYOUT_HEADER: 20,
254
+ DROPDOWN_LOCAL: 20,
255
+ SIDEBAR_CONTAINER: 30,
256
+ SIDEBAR_BACKDROP: 40,
257
+ SIDEBAR: 50,
258
+ DROPDOWN: 50,
259
+ CALENDAR_ANCHORED: 50,
260
+ LOADING_OVERLAY_DEFAULT: 50,
261
+ DRAWING_CANVAS_1: 51,
262
+ DRAWING_CANVAS_2: 52,
263
+ DRAWING: 53,
264
+ MODAL_OVERLAY: 54,
265
+ MODAL: 55,
266
+ CALENDAR_PORTAL: 60,
267
+ TOOLTIP: 70,
268
+ SELECT_CONTENT: 100,
269
+ TOP: 9999,
270
+ MODAL_Z_STEP: 10
271
+ };
245
272
  function Tooltip2(props) {
246
273
  const {
247
274
  children,
@@ -253,6 +280,7 @@ function Tooltip2(props) {
253
280
  arrowClassName = "",
254
281
  contentClassName = "",
255
282
  contentStyle = {},
283
+ containerStyle,
256
284
  offsetX = 0,
257
285
  offsetY = 2,
258
286
  delayDuration = 0,
@@ -272,7 +300,9 @@ function Tooltip2(props) {
272
300
  sideOffset,
273
301
  collisionPadding: 8,
274
302
  style: {
275
- transform: `translateX(${offsetX}px) translateY(${translateY}px)`
303
+ zIndex: Z_INDEX.TOOLTIP,
304
+ transform: `translateX(${offsetX}px) translateY(${translateY}px)`,
305
+ ...containerStyle
276
306
  },
277
307
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-[5px] break-words whitespace-normal", style: contentStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: contentClassName, children: [
278
308
  content && /* @__PURE__ */ jsxRuntime.jsx("span", { children: content }),
@@ -1319,31 +1349,6 @@ function Spinner(props) {
1319
1349
  }
1320
1350
  );
1321
1351
  }
1322
-
1323
- // src/config/zIndex.ts
1324
- var Z_INDEX = {
1325
- TABLE_COL_STICKY: 1,
1326
- TABLE_FIXED_CELL: 5,
1327
- TABLE_FIXED_HEADER_CELL: 10,
1328
- LOCAL_OVERLAY: 10,
1329
- LAYOUT_HEADER: 20,
1330
- DROPDOWN_LOCAL: 20,
1331
- SIDEBAR_CONTAINER: 30,
1332
- SIDEBAR_BACKDROP: 40,
1333
- SIDEBAR: 50,
1334
- DROPDOWN: 50,
1335
- CALENDAR_ANCHORED: 50,
1336
- LOADING_OVERLAY_DEFAULT: 50,
1337
- DRAWING_CANVAS_1: 51,
1338
- DRAWING_CANVAS_2: 52,
1339
- DRAWING: 53,
1340
- MODAL_OVERLAY: 54,
1341
- MODAL: 55,
1342
- CALENDAR_PORTAL: 60,
1343
- SELECT_CONTENT: 100,
1344
- TOP: 9999,
1345
- MODAL_Z_STEP: 10
1346
- };
1347
1352
  function LoadingOverlay(props) {
1348
1353
  const {
1349
1354
  isVisible,
@@ -1958,13 +1963,18 @@ function ToastProvider() {
1958
1963
  }
1959
1964
 
1960
1965
  // src/components/DatePicker/config/utils.ts
1966
+ function makeLocalDate(year, monthIndex, day) {
1967
+ const d = /* @__PURE__ */ new Date(0);
1968
+ d.setFullYear(year, monthIndex, day);
1969
+ return d;
1970
+ }
1961
1971
  function parseLocalYmd(ymd) {
1962
1972
  const m = ymd.trim().match(/^(\d{4})-(\d{2})-(\d{2})$/);
1963
1973
  if (!m) return null;
1964
1974
  const y = Number(m[1]);
1965
1975
  const mo = Number(m[2]) - 1;
1966
1976
  const d = Number(m[3]);
1967
- const dt = new Date(y, mo, d);
1977
+ const dt = makeLocalDate(y, mo, d);
1968
1978
  if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== d) return null;
1969
1979
  return dt;
1970
1980
  }
@@ -1998,7 +2008,7 @@ function isCalendarDayAfterMax(date, maxYmd) {
1998
2008
  return ax > bx;
1999
2009
  }
2000
2010
  function formatDate(date) {
2001
- const year = date.getFullYear();
2011
+ const year = String(date.getFullYear()).padStart(4, "0");
2002
2012
  const month = String(date.getMonth() + 1).padStart(2, "0");
2003
2013
  const day = String(date.getDate()).padStart(2, "0");
2004
2014
  return `${year}-${month}-${day}`;
@@ -2017,7 +2027,6 @@ function validateAndFormatInput(input) {
2017
2027
  if (numbers.length === 0) return "";
2018
2028
  const clampYear = (raw) => {
2019
2029
  const n = parseInt(raw, 10);
2020
- if (n < 1) return "0001";
2021
2030
  if (n > 9999) return "9999";
2022
2031
  return raw;
2023
2032
  };
@@ -2040,7 +2049,7 @@ function validateAndFormatInput(input) {
2040
2049
  let day = dayRaw;
2041
2050
  if (day.length === 2) {
2042
2051
  const dayNum = parseInt(day, 10);
2043
- const lastDayOfMonth = new Date(parseInt(year, 10), parseInt(month, 10), 0).getDate();
2052
+ const lastDayOfMonth = makeLocalDate(parseInt(year, 10), parseInt(month, 10), 0).getDate();
2044
2053
  if (dayNum < 1) day = "01";
2045
2054
  else if (dayNum > lastDayOfMonth) day = lastDayOfMonth.toString().padStart(2, "0");
2046
2055
  }
@@ -2048,7 +2057,7 @@ function validateAndFormatInput(input) {
2048
2057
  }
2049
2058
 
2050
2059
  // src/components/DatePicker/calendar/config/default.ts
2051
- var DEFAULT_CALENDAR_YEAR_HALF_SPAN = 25;
2060
+ var DEFAULT_CALENDAR_YEAR_HALF_SPAN = 50;
2052
2061
  var CALENDAR_WEEKDAY_LABELS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
2053
2062
  var CALENDAR_RANGE_HINT = {
2054
2063
  start: "\uC2DC\uC791 \uB0A0\uC9DC\uB97C \uC120\uD0DD\uD558\uC138\uC694",
@@ -2072,7 +2081,7 @@ function parseYmdDateString(value) {
2072
2081
  return parseLocalYmd(value);
2073
2082
  }
2074
2083
  function resolveCalendarYearBounds(anchorYear, calendarYearRange) {
2075
- const fallbackMin = anchorYear - DEFAULT_CALENDAR_YEAR_HALF_SPAN;
2084
+ const fallbackMin = Math.max(0, anchorYear - DEFAULT_CALENDAR_YEAR_HALF_SPAN);
2076
2085
  const fallbackMax = anchorYear + DEFAULT_CALENDAR_YEAR_HALF_SPAN;
2077
2086
  const rawMin = calendarYearRange?.minYear?.trim();
2078
2087
  const rawMax = calendarYearRange?.maxYear?.trim();
@@ -2084,7 +2093,7 @@ function resolveCalendarYearBounds(anchorYear, calendarYearRange) {
2084
2093
  if (Number.isNaN(minParsed) || Number.isNaN(maxParsed) || minParsed > maxParsed) {
2085
2094
  return { minYear: fallbackMin, maxYear: fallbackMax };
2086
2095
  }
2087
- return { minYear: minParsed, maxYear: maxParsed };
2096
+ return { minYear: Math.max(0, minParsed), maxYear: maxParsed };
2088
2097
  }
2089
2098
  function buildCalendarYearSelectOptions(maxDate, anchorYear = (/* @__PURE__ */ new Date()).getFullYear(), calendarYearRange) {
2090
2099
  const { minYear, maxYear } = resolveCalendarYearBounds(anchorYear, calendarYearRange);
@@ -2093,7 +2102,7 @@ function buildCalendarYearSelectOptions(maxDate, anchorYear = (/* @__PURE__ */ n
2093
2102
  for (let y = maxYear; y >= minYear; y--) {
2094
2103
  options.push({
2095
2104
  value: String(y),
2096
- label: `${y}\uB144`,
2105
+ label: `${String(y).padStart(4, "0")}\uB144`,
2097
2106
  disabled: maxSelectableYear !== null && y > maxSelectableYear
2098
2107
  });
2099
2108
  }
@@ -2115,8 +2124,8 @@ function buildCalendarMonthSelectOptions(viewYear, maxDate) {
2115
2124
  return options;
2116
2125
  }
2117
2126
  function getCalendarMonthGrid(year, monthIndex) {
2118
- const firstDay = new Date(year, monthIndex, 1);
2119
- const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
2127
+ const firstDay = makeLocalDate(year, monthIndex, 1);
2128
+ const daysInMonth = makeLocalDate(year, monthIndex + 1, 0).getDate();
2120
2129
  const leadingEmpty = firstDay.getDay();
2121
2130
  const totalCells = leadingEmpty + daysInMonth;
2122
2131
  const trailingEmpty = totalCells % 7 === 0 ? 0 : 7 - totalCells % 7;
@@ -2124,7 +2133,7 @@ function getCalendarMonthGrid(year, monthIndex) {
2124
2133
  }
2125
2134
  function disableNextCalendarMonth(year, monthIndex, maxDate) {
2126
2135
  if (maxDate === void 0) return false;
2127
- return isCalendarDayAfterMax(new Date(year, monthIndex + 1, 1), maxDate);
2136
+ return isCalendarDayAfterMax(makeLocalDate(year, monthIndex + 1, 1), maxDate);
2128
2137
  }
2129
2138
  function scrollOpenYearSelectCheckedIntoView() {
2130
2139
  requestAnimationFrame(() => {
@@ -2170,7 +2179,7 @@ function RenderCalendar(props) {
2170
2179
  } = props;
2171
2180
  const year = currentDate.getFullYear();
2172
2181
  const monthIndex = currentDate.getMonth();
2173
- const anchorYear = (/* @__PURE__ */ new Date()).getFullYear();
2182
+ const anchorYear = year;
2174
2183
  const disableNextMonth = disableNextCalendarMonth(year, monthIndex, maxDate);
2175
2184
  const { leadingEmpty, daysInMonth, trailingEmpty } = getCalendarMonthGrid(year, monthIndex);
2176
2185
  const yearOptions = buildCalendarYearSelectOptions(maxDate, anchorYear, calendarYearRange);
@@ -2184,7 +2193,7 @@ function RenderCalendar(props) {
2184
2193
  days.push(/* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-8", "aria-hidden": true }, `lead-${i}`));
2185
2194
  }
2186
2195
  for (let d = 1; d <= daysInMonth; d++) {
2187
- const date = new Date(year, monthIndex, d);
2196
+ const date = makeLocalDate(year, monthIndex, d);
2188
2197
  const dateFormatted = formatDate(date);
2189
2198
  const isToday = dateFormatted === todayFormatted;
2190
2199
  const isSelected = dateFormatted === selectedSingleYmd;
@@ -2283,7 +2292,7 @@ function RenderCalendar(props) {
2283
2292
  ]
2284
2293
  }
2285
2294
  ) : /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-lg font-semibold", children: [
2286
- year,
2295
+ String(year).padStart(4, "0"),
2287
2296
  "\uB144 ",
2288
2297
  monthIndex + 1,
2289
2298
  "\uC6D4"
@@ -2364,16 +2373,16 @@ function useCalendarState(props) {
2364
2373
  setIsCalendarOpen(false);
2365
2374
  };
2366
2375
  const goToPreviousMonth = () => {
2367
- setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1));
2376
+ setCurrentDate(makeLocalDate(currentDate.getFullYear(), currentDate.getMonth() - 1, 1));
2368
2377
  };
2369
2378
  const goToNextMonth = () => {
2370
- setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1));
2379
+ setCurrentDate(makeLocalDate(currentDate.getFullYear(), currentDate.getMonth() + 1, 1));
2371
2380
  };
2372
2381
  const handleYearChange = (year) => {
2373
- setCurrentDate(new Date(year, currentDate.getMonth(), 1));
2382
+ setCurrentDate(makeLocalDate(year, currentDate.getMonth(), 1));
2374
2383
  };
2375
2384
  const handleMonthChange = (month) => {
2376
- setCurrentDate(new Date(currentDate.getFullYear(), month, 1));
2385
+ setCurrentDate(makeLocalDate(currentDate.getFullYear(), month, 1));
2377
2386
  };
2378
2387
  return {
2379
2388
  isCalendarOpen,
@@ -2500,6 +2509,7 @@ function DatePickerRange(props) {
2500
2509
  return;
2501
2510
  }
2502
2511
  onRangeChange?.(formatted, endInputValue);
2512
+ if (isCalendarOpen && calendarPosition === "start") navigateToDateValue(formatted);
2503
2513
  } else if (formatted.length === 0) {
2504
2514
  onRangeChange?.(formatted, endInputValue);
2505
2515
  }
@@ -2513,6 +2523,7 @@ function DatePickerRange(props) {
2513
2523
  return;
2514
2524
  }
2515
2525
  onRangeChange?.(startInputValue, formatted);
2526
+ if (isCalendarOpen && calendarPosition === "end") navigateToDateValue(formatted);
2516
2527
  } else if (formatted.length === 0) {
2517
2528
  onRangeChange?.(startInputValue, formatted);
2518
2529
  }
@@ -2687,6 +2698,7 @@ function DatePickerSingle(props) {
2687
2698
  autoDatePosition,
2688
2699
  containerRef,
2689
2700
  toggleCalendar,
2701
+ navigateToDateValue,
2690
2702
  closeCalendar,
2691
2703
  goToPreviousMonth,
2692
2704
  goToNextMonth,
@@ -2704,7 +2716,7 @@ function DatePickerSingle(props) {
2704
2716
  const dateMatch = formatted.match(/^(\d{4})-(\d{2})-(\d{2})$/);
2705
2717
  if (dateMatch) {
2706
2718
  const [, year, month, day] = dateMatch;
2707
- const date = new Date(
2719
+ const date = makeLocalDate(
2708
2720
  Number.parseInt(year, 10),
2709
2721
  Number.parseInt(month, 10) - 1,
2710
2722
  Number.parseInt(day, 10)
@@ -2716,6 +2728,7 @@ function DatePickerSingle(props) {
2716
2728
  return;
2717
2729
  }
2718
2730
  onChange?.(formatted);
2731
+ if (isCalendarOpen) navigateToDateValue(formatted);
2719
2732
  }
2720
2733
  }
2721
2734
  } else {
@@ -3384,8 +3397,7 @@ function ModalContent(props) {
3384
3397
  {
3385
3398
  ref,
3386
3399
  className: cn(
3387
- "fixed left-[50%] top-[50%] max-h-[85vh] z-55 flex flex-col w-full max-w-lg translate-x-[-50%] translate-y-[-50%] bg-white rounded-lg overflow-hidden shadow-xl duration-200",
3388
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
3400
+ "fixed left-[50%] top-[50%] max-h-[85vh] z-55 flex flex-col w-full max-w-lg translate-x-[-50%] translate-y-[-50%] bg-white rounded-lg overflow-hidden shadow-xl",
3389
3401
  className
3390
3402
  ),
3391
3403
  style: zIndex !== void 0 ? { zIndex } : void 0,
@@ -3396,7 +3408,7 @@ function ModalContent(props) {
3396
3408
  );
3397
3409
  }
3398
3410
  function ModalOverlay(props) {
3399
- const { isOpen: isOpen2, onClose, className, closeOnOverlayClick = true, zIndex } = props;
3411
+ const { ref, isOpen: isOpen2, onClose, className, closeOnOverlayClick = true, zIndex } = props;
3400
3412
  if (!isOpen2) return null;
3401
3413
  const handleOverlayClick = (e) => {
3402
3414
  if (closeOnOverlayClick && e.target === e.currentTarget) {
@@ -3406,9 +3418,10 @@ function ModalOverlay(props) {
3406
3418
  return /* @__PURE__ */ jsxRuntime.jsx(
3407
3419
  "div",
3408
3420
  {
3421
+ ref,
3409
3422
  className: cn(
3410
3423
  "fixed inset-0 z-54 bg-black/50",
3411
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
3424
+ "animate-in fade-in-0 duration-150",
3412
3425
  className
3413
3426
  ),
3414
3427
  style: zIndex !== void 0 ? { zIndex } : void 0,
@@ -3510,7 +3523,7 @@ function Modal(props) {
3510
3523
  } = props;
3511
3524
  const idRef = React6.useRef(/* @__PURE__ */ Symbol("modal"));
3512
3525
  const [depth, setDepth] = React6.useState(0);
3513
- React6.useEffect(() => {
3526
+ React6.useLayoutEffect(() => {
3514
3527
  if (!isOpen2) return;
3515
3528
  const id = idRef.current;
3516
3529
  const d = modalStack.push(id);
@@ -3547,12 +3560,22 @@ function Modal(props) {
3547
3560
  {
3548
3561
  isOpen: isOpen2,
3549
3562
  onClose,
3550
- className: overlayClassName,
3563
+ className: cn(overlayClassName, depth > 1 && "bg-black/20"),
3551
3564
  closeOnOverlayClick,
3552
3565
  zIndex: overlayZ
3553
3566
  }
3554
3567
  ),
3555
- /* @__PURE__ */ jsxRuntime.jsx(ModalContent, { className: contentClassName, zIndex: contentZ, children })
3568
+ /* @__PURE__ */ jsxRuntime.jsx(
3569
+ ModalContent,
3570
+ {
3571
+ className: cn(
3572
+ contentClassName,
3573
+ depth > 1 && "shadow-[0_0_0_1px_rgba(255,255,255,0.12),0_20px_50px_-5px_rgba(0,0,0,0.4)]"
3574
+ ),
3575
+ zIndex: contentZ,
3576
+ children
3577
+ }
3578
+ )
3556
3579
  ] });
3557
3580
  }
3558
3581
  function ConfirmModal(props) {
@@ -3652,9 +3675,10 @@ function ConfirmModal(props) {
3652
3675
  ] }),
3653
3676
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-8 items-center justify-end gap-2", children: [
3654
3677
  !isHideOkButton && /* @__PURE__ */ jsxRuntime.jsx(
3655
- Button,
3678
+ DebouncedButton,
3656
3679
  {
3657
3680
  ref: okButtonRef,
3681
+ debounceDelay: 500,
3658
3682
  variant: "outline",
3659
3683
  onClick: handleOkClick,
3660
3684
  className: "focus-visible:ring-2 focus-visible:ring-blue-400 focus-visible:ring-offset-1",
@@ -4052,7 +4076,7 @@ function TableHeader(props) {
4052
4076
  const subTitleClasses = column.key === "subTitle" ? "inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800" : "";
4053
4077
  if (column.align === "left") {
4054
4078
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex item-center w-full", children: [
4055
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pl-2 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) }),
4079
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pl-3 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) }),
4056
4080
  column.sortable && /* @__PURE__ */ jsxRuntime.jsx(
4057
4081
  "div",
4058
4082
  {
@@ -4083,7 +4107,7 @@ function TableHeader(props) {
4083
4107
  children: renderSortIcon(column.key)
4084
4108
  }
4085
4109
  ),
4086
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pr-2 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) })
4110
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pr-3 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) })
4087
4111
  ] });
4088
4112
  }
4089
4113
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-1.5 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title });
@@ -4454,7 +4478,7 @@ function SkeletonTd(props) {
4454
4478
  return /* @__PURE__ */ jsxRuntime.jsx(
4455
4479
  "td",
4456
4480
  {
4457
- className: `${col.key === "__checkbox__" ? "p-0" : "px-2 py-[6.8px]"} whitespace-nowrap text-sm border-r border-b border-gray-200/70 last:border-r-0`,
4481
+ className: `${col.key === "__checkbox__" ? "p-0" : "px-2 py-4"} whitespace-nowrap text-sm border-r border-b border-gray-200/70 last:border-r-0`,
4458
4482
  style: {
4459
4483
  width: col.width,
4460
4484
  minWidth: col.minWidth || col.width,
@@ -4526,7 +4550,7 @@ function TableCellContent(props) {
4526
4550
  "div",
4527
4551
  {
4528
4552
  ref: textRef,
4529
- className: "ellipsis-1-line table-item hover:text-main cursor-pointer w-full min-w-0",
4553
+ className: `ellipsis-1-line table-item w-full min-w-0 ${onCellClick ? "hover:text-main cursor-pointer" : "cursor-default"}`,
4530
4554
  style: { textAlign },
4531
4555
  onClick: onCellClick,
4532
4556
  children: shouldShowTooltip ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip2, { content: tooltipText, position: "bottom", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: cellContent }) }) : cellContent
@@ -4995,7 +5019,7 @@ function Table(props) {
4995
5019
  id: `${col.key}-body`,
4996
5020
  "data-row-cell": "true",
4997
5021
  "data-col-key": col.key,
4998
- className: `${isCheckbox ? "p-0" : "px-2 py-[6.8px]"} whitespace-nowrap text-sm text-gray-900 border-r border-b border-gray-200 last:border-r-0 bg-inherit group-hover:bg-gray-100 transition-all`,
5022
+ className: `${isCheckbox ? "p-0" : "px-2 py-4"} whitespace-nowrap text-sm text-gray-900 border-r border-b border-gray-200 last:border-r-0 bg-inherit group-hover:bg-gray-100 transition-all`,
4999
5023
  style: {
5000
5024
  width,
5001
5025
  minWidth: minWidth || width,
@@ -5012,7 +5036,7 @@ function Table(props) {
5012
5036
  tooltipText: String(record[col.key] ?? ""),
5013
5037
  align: align ?? "",
5014
5038
  tooltipConfig: col.key === "__checkbox__" ? false : tooltipConfig,
5015
- onCellClick: col.key !== "__checkbox__" ? () => onRowClickRef.current?.(record, rowIdx) : void 0
5039
+ onCellClick: col.key !== "__checkbox__" && onRowClickRef.current ? () => onRowClickRef.current?.(record, rowIdx) : void 0
5016
5040
  }
5017
5041
  ) })
5018
5042
  },
@@ -5087,7 +5111,7 @@ function Table(props) {
5087
5111
  const rest = baseRows.filter((row) => !effectiveRowOrder.includes(String(getRowKey(row.original, row.index))));
5088
5112
  return [...ordered, ...rest];
5089
5113
  }, [baseRows, effectiveRowOrder, getRowKey]);
5090
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded table-shadow", children: [
5114
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded shadow-panel", children: [
5091
5115
  /* @__PURE__ */ jsxRuntime.jsx(
5092
5116
  "div",
5093
5117
  {
@@ -5111,7 +5135,7 @@ function Table(props) {
5111
5135
  isColumnDraggable
5112
5136
  }
5113
5137
  ),
5114
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "w-full h-full", children: showSkeleton ? Array.from({ length: 15 }).map((_, rowIdx) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "hover:bg-gray-50", children: [
5138
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "w-full h-full", children: showSkeleton ? Array.from({ length: 3 }).map((_, rowIdx) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "hover:bg-gray-50", children: [
5115
5139
  leadingPinnedCols.map((col, idx) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonTd, { col, showSquare: idx === 0 && !!checkboxInfo }, `leading-${idx}`)),
5116
5140
  leftColspan > 0 && /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: leftColspan, style: { padding: 0, border: "none" } }),
5117
5141
  virtualItems.map((vc) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonTd, { col: groupCols[vc.index] }, `group-${vc.index}`)),
@@ -6825,7 +6849,8 @@ function InputField(props) {
6825
6849
  maxLength,
6826
6850
  className = "",
6827
6851
  type = "input",
6828
- numbersOnly = false
6852
+ numbersOnly = false,
6853
+ autoComplete
6829
6854
  } = config;
6830
6855
  const inputType = type === "email" ? "email" : type === "password" ? "password" : "text";
6831
6856
  if (readOnly) {
@@ -6850,6 +6875,7 @@ function InputField(props) {
6850
6875
  maxLength,
6851
6876
  status: "default",
6852
6877
  className: formControlClass(hasError),
6878
+ autoComplete,
6853
6879
  bare: true,
6854
6880
  onChange: handleChange
6855
6881
  }
@@ -7555,7 +7581,8 @@ function SubmitFormRoot(props) {
7555
7581
  className = "",
7556
7582
  formClassName,
7557
7583
  gridClassName = "grid-cols-12",
7558
- mode = "onSubmit"
7584
+ mode = "onSubmit",
7585
+ autoComplete
7559
7586
  } = props;
7560
7587
  const methods = reactHookForm.useForm({
7561
7588
  resolver: zod.zodResolver(schema),
@@ -7578,6 +7605,7 @@ function SubmitFormRoot(props) {
7578
7605
  id: formId,
7579
7606
  onSubmit: handleSubmit,
7580
7607
  className: cn2(SUBMIT_FORM_CLASS, formClassName, className),
7608
+ autoComplete,
7581
7609
  noValidate: true,
7582
7610
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid ${gridClassName} items-stretch gap-0`, children })
7583
7611
  }
@@ -7605,7 +7633,8 @@ function PageFilter(props) {
7605
7633
  colGap = 0,
7606
7634
  submitButtonText = "\uAC80\uC0C9",
7607
7635
  resetButtonText = "\uCD08\uAE30\uD654",
7608
- values
7636
+ values,
7637
+ primaryColor
7609
7638
  } = props;
7610
7639
  const [localValues, setLocalValues] = React6.useState(values);
7611
7640
  const initialValuesRef = React6.useRef(values);
@@ -7644,7 +7673,17 @@ function PageFilter(props) {
7644
7673
  const rowGap2 = index !== 0 ? option.label ? gap : 5 : 0;
7645
7674
  switch (option.type) {
7646
7675
  case "input":
7647
- return /* @__PURE__ */ jsxRuntime.jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsxRuntime.jsx(Input2, { placeholder: option.placeholder, value: currentValue, onChange: handleInputChange(optionKey) }) }, String(optionKey));
7676
+ return /* @__PURE__ */ jsxRuntime.jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsxRuntime.jsx(
7677
+ Input2,
7678
+ {
7679
+ placeholder: option.placeholder,
7680
+ value: currentValue,
7681
+ onChange: handleInputChange(optionKey),
7682
+ onKeyDown: (e) => {
7683
+ if (e.key === "Enter") handleSubmit();
7684
+ }
7685
+ }
7686
+ ) }, String(optionKey));
7648
7687
  case "select":
7649
7688
  return /* @__PURE__ */ jsxRuntime.jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsxRuntime.jsx(
7650
7689
  Select2,
@@ -7653,6 +7692,7 @@ function PageFilter(props) {
7653
7692
  onChange: handleSelectChange(optionKey),
7654
7693
  options: option.options,
7655
7694
  placeholder: "\uC120\uD0DD",
7695
+ canReset: true,
7656
7696
  containerClassName: option.containerClassName ?? "w-30"
7657
7697
  }
7658
7698
  ) }, String(optionKey));
@@ -7705,22 +7745,109 @@ function PageFilter(props) {
7705
7745
  "div",
7706
7746
  {
7707
7747
  className: cn(
7708
- "flex flex-col gap-3 bg-white py-3 px-5 border-t-main border-t-1 shadow-page-filter",
7748
+ "flex flex-col gap-3 bg-white py-3 px-5 border-t-main border-t-1 shadow-panel",
7709
7749
  containerClassName
7710
7750
  ),
7711
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: [
7712
- rows.map((row) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row min-h-12", children: row.options.map((option, index) => renderFilterOption(option, rowGap, index)) }, row.options.map((opt) => String(opt.key)).join("_"))),
7713
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-2 bottom-2 flex justify-end gap-2 pt-2", children: [
7714
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7715
- onReset && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7716
- ] })
7717
- ] })
7751
+ style: primaryColor ? { borderTopColor: primaryColor } : void 0,
7752
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: rows.map((row, ix) => {
7753
+ const isLastRow = rows.length - 1 === ix;
7754
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row min-h-12", children: [
7755
+ row.options.map((option, index) => renderFilterOption(option, rowGap, index)),
7756
+ isLastRow && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-4 flex flex-row items-center gap-2", children: [
7757
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7758
+ onReset && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7759
+ ] })
7760
+ ] }, row.options.map((opt) => String(opt.key)).join("_"));
7761
+ }) })
7718
7762
  }
7719
7763
  );
7720
7764
  }
7765
+ var VARIANT_STYLES = {
7766
+ light: {
7767
+ container: "bg-white border-b border-gray-200",
7768
+ activeTab: "bg-gray-50 border-gray-200 text-gray-800 shadow-sm",
7769
+ inactiveTab: "bg-white border-gray-100 text-gray-400 hover:text-gray-600 hover:border-gray-200 hover:bg-gray-50",
7770
+ activeText: "font-semibold text-gray-800",
7771
+ inactiveText: "font-normal",
7772
+ indicator: "bg-blue-500",
7773
+ closeBtn: "rounded hover:bg-gray-300/60",
7774
+ closeBtnWH: "w-3.5 h-3.5",
7775
+ closeBtnSize: 10,
7776
+ plusBtnArea: "border-l border-gray-100 bg-white",
7777
+ plusBtn: "text-gray-400 hover:text-gray-600 hover:bg-gray-100",
7778
+ fadeOpacity: 0.12,
7779
+ tabPy: "py-1.5",
7780
+ tabPx: "px-3",
7781
+ tabTextSize: "text-xs",
7782
+ scrollPadding: "px-3 pt-1.5",
7783
+ rounded: "rounded-t-md"
7784
+ },
7785
+ dark: {
7786
+ container: "bg-gray-900 border-b border-gray-700",
7787
+ activeTab: "bg-gray-800 border-gray-600 text-white shadow-sm",
7788
+ inactiveTab: "bg-gray-900 border-gray-700/50 text-gray-500 hover:text-gray-300 hover:border-gray-600 hover:bg-gray-800",
7789
+ activeText: "font-semibold text-white",
7790
+ inactiveText: "font-normal",
7791
+ indicator: "bg-indigo-400",
7792
+ closeBtn: "rounded hover:bg-gray-600/60",
7793
+ closeBtnWH: "w-3.5 h-3.5",
7794
+ closeBtnSize: 10,
7795
+ plusBtnArea: "border-l border-gray-700 bg-gray-900",
7796
+ plusBtn: "text-gray-500 hover:text-gray-300 hover:bg-gray-700",
7797
+ fadeOpacity: 0.4,
7798
+ tabPy: "py-1.5",
7799
+ tabPx: "px-3",
7800
+ tabTextSize: "text-xs",
7801
+ scrollPadding: "px-3 pt-1.5",
7802
+ rounded: "rounded-t-md"
7803
+ },
7804
+ "system-light": {
7805
+ container: "bg-gray-200 border-b border-gray-300",
7806
+ activeTab: "bg-white border-gray-300 text-slate-800 shadow-sm",
7807
+ inactiveTab: "bg-transparent border-gray-300/80 text-slate-500 hover:text-slate-700 hover:bg-[#efefef] hover:border-gray-300",
7808
+ activeText: "font-semibold text-slate-800",
7809
+ inactiveText: "font-medium",
7810
+ indicator: "bg-[#2b2b2b]",
7811
+ closeBtn: "ml-auto text-slate-400 hover:text-slate-700",
7812
+ closeBtnWH: "w-4 h-4",
7813
+ closeBtnSize: 13,
7814
+ plusBtnArea: "border-l border-gray-300 bg-gray-200",
7815
+ plusBtn: "text-slate-400 hover:text-slate-600 hover:bg-gray-300",
7816
+ fadeOpacity: 0.15,
7817
+ tabPy: "py-2.5",
7818
+ tabPx: "px-5",
7819
+ tabTextSize: "text-sm",
7820
+ scrollPadding: "px-3 pt-2",
7821
+ rounded: "rounded-t-none"
7822
+ },
7823
+ "system-dark": {
7824
+ container: "bg-slate-900 border-b border-slate-700",
7825
+ activeTab: "bg-slate-800 border-slate-600 text-slate-100 shadow-sm",
7826
+ inactiveTab: "bg-transparent border-slate-700/50 text-slate-400 hover:text-slate-200 hover:bg-slate-800/60 hover:border-slate-700",
7827
+ activeText: "font-semibold text-slate-100",
7828
+ inactiveText: "font-medium",
7829
+ indicator: "bg-indigo-400",
7830
+ closeBtn: "ml-auto text-slate-500 hover:text-slate-200",
7831
+ closeBtnWH: "w-4 h-4",
7832
+ closeBtnSize: 13,
7833
+ plusBtnArea: "border-l border-slate-700 bg-slate-900",
7834
+ plusBtn: "text-slate-400 hover:text-slate-200 hover:bg-slate-700",
7835
+ fadeOpacity: 0.45,
7836
+ tabPy: "py-2.5",
7837
+ tabPx: "px-5",
7838
+ tabTextSize: "text-sm",
7839
+ scrollPadding: "px-4 pt-2",
7840
+ rounded: "rounded-t-none"
7841
+ }
7842
+ };
7721
7843
  var PLUS_BTN_WIDTH = 36;
7844
+ function easedFade(dir, opacity) {
7845
+ const c = (t) => `rgba(0,0,0,${(opacity * t).toFixed(3)})`;
7846
+ return `linear-gradient(${dir}, ${c(1)} 0%, ${c(0.72)} 20%, ${c(0.38)} 45%, ${c(0.1)} 70%, transparent 100%)`;
7847
+ }
7722
7848
  function MultiTabBar(props) {
7723
- const { tabs, activeTabId, onTabClick, onTabClose, onTabAdd } = props;
7849
+ const { tabs, activeTabId, onTabClick, onTabClose, onTabAdd, variant = "light", primaryColor } = props;
7850
+ const s = VARIANT_STYLES[variant];
7724
7851
  const scrollRef = React6.useRef(null);
7725
7852
  const tabRefs = React6.useRef(/* @__PURE__ */ new Map());
7726
7853
  const [showLeftFade, setShowLeftFade] = React6.useState(false);
@@ -7773,13 +7900,23 @@ function MultiTabBar(props) {
7773
7900
  const handleStopDrag = () => {
7774
7901
  isDragging.current = false;
7775
7902
  };
7903
+ React6.useEffect(() => {
7904
+ const el = scrollRef.current;
7905
+ if (!el) return;
7906
+ const onWheel = (e) => {
7907
+ e.preventDefault();
7908
+ el.scrollLeft += e.deltaY || e.deltaX;
7909
+ };
7910
+ el.addEventListener("wheel", onWheel, { passive: false });
7911
+ return () => el.removeEventListener("wheel", onWheel);
7912
+ }, []);
7776
7913
  if (tabs.length === 0) return null;
7777
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 w-full overflow-hidden bg-white border-b border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-stretch", children: [
7914
+ 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: [
7778
7915
  showLeftFade && /* @__PURE__ */ jsxRuntime.jsx(
7779
7916
  "div",
7780
7917
  {
7781
7918
  className: "absolute left-0 top-0 bottom-0 w-10 pointer-events-none z-10",
7782
- style: { background: "linear-gradient(to right, white 30%, transparent)" }
7919
+ style: { background: easedFade("to right", s.fadeOpacity) }
7783
7920
  }
7784
7921
  ),
7785
7922
  showRightFade && /* @__PURE__ */ jsxRuntime.jsx(
@@ -7788,7 +7925,7 @@ function MultiTabBar(props) {
7788
7925
  className: "absolute top-0 bottom-0 w-10 pointer-events-none z-10",
7789
7926
  style: {
7790
7927
  right: PLUS_BTN_WIDTH,
7791
- background: "linear-gradient(to left, white 30%, transparent)"
7928
+ background: easedFade("to left", s.fadeOpacity)
7792
7929
  }
7793
7930
  }
7794
7931
  ),
@@ -7796,7 +7933,7 @@ function MultiTabBar(props) {
7796
7933
  "div",
7797
7934
  {
7798
7935
  ref: scrollRef,
7799
- className: "flex-1 min-w-0 flex items-end gap-0.5 px-3 pt-1.5 overflow-x-auto [&::-webkit-scrollbar]:hidden",
7936
+ className: `flex-1 min-w-0 flex items-end gap-0.5 ${s.scrollPadding} overflow-x-auto [&::-webkit-scrollbar]:hidden`,
7800
7937
  style: { scrollbarWidth: "none" },
7801
7938
  onScroll: updateFades,
7802
7939
  onMouseDown: handleMouseDown,
@@ -7817,17 +7954,23 @@ function MultiTabBar(props) {
7817
7954
  if (!isActive) onTabClick(tab.id);
7818
7955
  },
7819
7956
  className: `
7820
- group relative flex items-center gap-1.5 px-3 py-1.5 flex-shrink-0
7821
- rounded-t-md border border-b-0 cursor-pointer select-none
7957
+ group relative flex items-center gap-1.5 ${s.tabPx} ${s.tabPy} flex-shrink-0
7958
+ ${s.rounded} border border-b-0 cursor-pointer select-none
7822
7959
  transition-colors duration-100
7823
- ${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"}
7960
+ ${isActive ? s.activeTab : s.inactiveTab}
7824
7961
  `,
7825
7962
  children: [
7826
- isActive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 h-0.5 rounded-t-md bg-blue-500" }),
7963
+ isActive && /* @__PURE__ */ jsxRuntime.jsx(
7964
+ "div",
7965
+ {
7966
+ className: `absolute top-0 left-0 right-0 h-0.5 ${s.rounded} ${s.indicator}`,
7967
+ style: primaryColor ? { backgroundColor: primaryColor } : void 0
7968
+ }
7969
+ ),
7827
7970
  /* @__PURE__ */ jsxRuntime.jsx(
7828
7971
  "span",
7829
7972
  {
7830
- className: `text-xs max-w-35 truncate leading-none ${isActive ? "font-semibold text-gray-800" : "font-normal"}`,
7973
+ className: `${s.tabTextSize} max-w-35 truncate leading-none ${isActive ? s.activeText : s.inactiveText}`,
7831
7974
  children: tab.label
7832
7975
  }
7833
7976
  ),
@@ -7839,11 +7982,12 @@ function MultiTabBar(props) {
7839
7982
  onTabClose(tab.id);
7840
7983
  },
7841
7984
  className: `
7842
- flex-shrink-0 w-3.5 h-3.5 flex items-center justify-center
7843
- rounded hover:bg-gray-300/60 transition-all duration-100 cursor-pointer
7985
+ flex-shrink-0 ${s.closeBtnWH} flex items-center justify-center
7986
+ transition-all duration-100 cursor-pointer
7987
+ ${s.closeBtn}
7844
7988
  ${isActive ? "opacity-100" : "opacity-40 group-hover:opacity-60"}
7845
7989
  `,
7846
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 10, strokeWidth: 2.5 })
7990
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: s.closeBtnSize, strokeWidth: 2.5 })
7847
7991
  }
7848
7992
  )
7849
7993
  ]
@@ -7856,14 +8000,14 @@ function MultiTabBar(props) {
7856
8000
  onTabAdd && /* @__PURE__ */ jsxRuntime.jsx(
7857
8001
  "div",
7858
8002
  {
7859
- className: "flex-shrink-0 flex items-center justify-center border-l border-gray-100 bg-white",
8003
+ className: `flex-shrink-0 flex items-center justify-center ${s.plusBtnArea}`,
7860
8004
  style: { width: PLUS_BTN_WIDTH },
7861
8005
  children: /* @__PURE__ */ jsxRuntime.jsx(
7862
8006
  "button",
7863
8007
  {
7864
8008
  onClick: onTabAdd,
7865
8009
  title: "\uD604\uC7AC \uD398\uC774\uC9C0\uB97C \uC0C8 \uD0ED\uC73C\uB85C \uC5F4\uAE30",
7866
- 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",
8010
+ className: `w-6 h-6 flex items-center justify-center rounded cursor-pointer transition-colors ${s.plusBtn}`,
7867
8011
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 13, strokeWidth: 2 })
7868
8012
  }
7869
8013
  )
@@ -8648,19 +8792,226 @@ function FileUploader(props) {
8648
8792
  /* @__PURE__ */ jsxRuntime.jsx(FilePreviewViewer, { ...viewer.viewerProps, fileTypes, fileNames: files.map((f) => f.name) })
8649
8793
  ] });
8650
8794
  }
8795
+ var VARIANT_STYLES2 = {
8796
+ light: {
8797
+ aside: "bg-white border-r border-gray-200",
8798
+ sectionTitle: "text-xs font-semibold text-gray-500 tracking-wider mb-3",
8799
+ itemActive: "bg-blue-50 text-blue-600",
8800
+ itemInactive: "text-gray-700 hover:bg-gray-100",
8801
+ subItemActive: "text-blue-600 font-medium",
8802
+ subItemInactive: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
8803
+ childGroupBorder: "border-gray-100",
8804
+ childActive: "bg-blue-50 text-blue-600 font-medium",
8805
+ childInactive: "text-gray-600 hover:bg-gray-50 hover:text-gray-900",
8806
+ grandchildActive: "bg-blue-50 text-blue-600 font-medium",
8807
+ grandchildInactive: "text-gray-500 hover:bg-gray-50 hover:text-gray-900",
8808
+ collapseBtn: "bg-gray-50 hover:bg-gray-100",
8809
+ collapseIcon: "var(--color-sub-darkgray)",
8810
+ rounded: "rounded-lg",
8811
+ itemPy: "py-2",
8812
+ childPy: "py-1.5",
8813
+ grandchildPy: "py-1",
8814
+ itemFont: "font-semibold",
8815
+ itemTextSize: "text-sm",
8816
+ grandchildTextSize: "text-xs",
8817
+ iconClass: "w-4 h-4 flex-shrink-0",
8818
+ activeItemStyle: {},
8819
+ activeChildStyle: {},
8820
+ activeGrandchildStyle: {},
8821
+ footerBorder: "border-t border-gray-200"
8822
+ },
8823
+ dark: {
8824
+ aside: "bg-gray-900 border-r border-gray-700",
8825
+ sectionTitle: "text-xs font-semibold text-gray-400 tracking-wider mb-3",
8826
+ itemActive: "bg-gray-700 text-white",
8827
+ itemInactive: "text-gray-300 hover:bg-gray-800",
8828
+ subItemActive: "text-blue-400 font-medium",
8829
+ subItemInactive: "text-gray-400 hover:bg-gray-800 hover:text-gray-100",
8830
+ childGroupBorder: "border-gray-700",
8831
+ childActive: "bg-gray-700 text-white font-medium",
8832
+ childInactive: "text-gray-400 hover:bg-gray-800 hover:text-gray-100",
8833
+ grandchildActive: "bg-gray-700 text-blue-400 font-medium",
8834
+ grandchildInactive: "text-gray-500 hover:bg-gray-800 hover:text-gray-100",
8835
+ collapseBtn: "bg-gray-800 hover:bg-gray-700",
8836
+ collapseIcon: "#9ca3af",
8837
+ rounded: "rounded-lg",
8838
+ itemPy: "py-2",
8839
+ childPy: "py-1.5",
8840
+ grandchildPy: "py-1",
8841
+ itemFont: "font-semibold",
8842
+ itemTextSize: "text-sm",
8843
+ grandchildTextSize: "text-xs",
8844
+ iconClass: "w-4 h-4 flex-shrink-0",
8845
+ activeItemStyle: {},
8846
+ activeChildStyle: {},
8847
+ activeGrandchildStyle: {},
8848
+ footerBorder: "border-t border-gray-700"
8849
+ },
8850
+ "system-dark": {
8851
+ aside: "bg-slate-900 border-r border-slate-700",
8852
+ sectionTitle: "text-[10px] font-bold text-slate-500 uppercase tracking-[0.12em] mb-2 pb-2 border-b border-slate-700/70",
8853
+ itemActive: "bg-slate-800 text-white",
8854
+ itemInactive: "text-slate-300 hover:bg-slate-800/60 hover:text-white",
8855
+ subItemActive: "text-slate-100 font-medium",
8856
+ subItemInactive: "text-slate-400 hover:bg-slate-800/50 hover:text-slate-200",
8857
+ childGroupBorder: "border-slate-700/60",
8858
+ childActive: "bg-slate-800/70 text-slate-100 font-medium",
8859
+ childInactive: "text-slate-400 hover:bg-slate-800/50 hover:text-slate-200",
8860
+ grandchildActive: "text-slate-100 font-medium",
8861
+ grandchildInactive: "text-slate-500 hover:bg-slate-800/50 hover:text-slate-200",
8862
+ collapseBtn: "bg-slate-800 hover:bg-slate-700",
8863
+ collapseIcon: "#94a3b8",
8864
+ rounded: "rounded-none",
8865
+ itemPy: "py-3",
8866
+ childPy: "py-[10px]",
8867
+ grandchildPy: "py-2",
8868
+ itemFont: "font-medium",
8869
+ itemTextSize: "text-sm",
8870
+ grandchildTextSize: "text-xs",
8871
+ iconClass: "w-4.5 h-4.5 flex-shrink-0",
8872
+ activeItemStyle: { borderLeft: "3px solid #818cf8", paddingLeft: "9px" },
8873
+ activeChildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "14px" },
8874
+ activeGrandchildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "10px" },
8875
+ footerBorder: "border-t border-slate-700"
8876
+ },
8877
+ "system-light": {
8878
+ aside: "bg-gray-50 border-r border-gray-200",
8879
+ sectionTitle: "text-[10px] font-bold text-slate-400 uppercase tracking-[0.12em] mb-2 pb-2 border-b border-gray-200",
8880
+ itemActive: "font-medium",
8881
+ itemInactive: "text-slate-700 hover:bg-gray-100",
8882
+ subItemActive: "text-[#2b2b2b] font-medium",
8883
+ subItemInactive: "text-slate-500 hover:bg-gray-100 hover:text-slate-800",
8884
+ childGroupBorder: "border-gray-200",
8885
+ childActive: "font-medium",
8886
+ childInactive: "text-slate-500 hover:bg-gray-100 hover:text-slate-800",
8887
+ grandchildActive: "text-[#2b2b2b] font-medium",
8888
+ grandchildInactive: "text-slate-500 hover:bg-gray-100 hover:text-slate-800",
8889
+ collapseBtn: "bg-gray-100 hover:bg-gray-200",
8890
+ collapseIcon: "#64748b",
8891
+ rounded: "rounded-none",
8892
+ itemPy: "py-3",
8893
+ childPy: "py-[10px]",
8894
+ grandchildPy: "py-2",
8895
+ itemFont: "font-medium",
8896
+ itemTextSize: "text-[15px]",
8897
+ grandchildTextSize: "text-sm",
8898
+ iconClass: "w-4.5 h-4.5 flex-shrink-0",
8899
+ activeItemStyle: {
8900
+ color: "#2b2b2b",
8901
+ backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8902
+ borderLeft: "3px solid #2b2b2b",
8903
+ paddingLeft: "9px"
8904
+ },
8905
+ activeChildStyle: {
8906
+ color: "#2b2b2b",
8907
+ backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8908
+ borderLeft: "2px solid #2b2b2b",
8909
+ paddingLeft: "14px"
8910
+ },
8911
+ activeGrandchildStyle: {
8912
+ color: "#2b2b2b",
8913
+ backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8914
+ borderLeft: "2px solid #2b2b2b",
8915
+ paddingLeft: "10px"
8916
+ },
8917
+ footerBorder: "border-t border-gray-200"
8918
+ }
8919
+ };
8920
+ function tintedStyle(color) {
8921
+ return {
8922
+ color,
8923
+ backgroundColor: `color-mix(in srgb, ${color} 12%, transparent)`
8924
+ };
8925
+ }
8926
+ function textStyle(color) {
8927
+ return { color };
8928
+ }
8929
+ function solidStyle(color) {
8930
+ return {
8931
+ backgroundColor: `color-mix(in srgb, ${color} 25%, transparent)`,
8932
+ color: "#ffffff",
8933
+ boxShadow: `inset 3px 0 0 ${color}`
8934
+ };
8935
+ }
8936
+ var ACCENT_APPLIERS = {
8937
+ light: {
8938
+ itemActive: tintedStyle,
8939
+ subItemActive: textStyle,
8940
+ childActive: tintedStyle,
8941
+ grandchildActive: textStyle
8942
+ },
8943
+ dark: {
8944
+ itemActive: textStyle,
8945
+ subItemActive: textStyle,
8946
+ childActive: textStyle,
8947
+ grandchildActive: textStyle
8948
+ },
8949
+ "system-dark": {
8950
+ itemActive: (c) => ({
8951
+ ...solidStyle(c),
8952
+ boxShadow: void 0,
8953
+ borderLeft: `3px solid ${c}`,
8954
+ paddingLeft: "9px"
8955
+ }),
8956
+ subItemActive: textStyle,
8957
+ childActive: (c) => ({
8958
+ ...solidStyle(c),
8959
+ boxShadow: void 0,
8960
+ borderLeft: `2px solid ${c}`,
8961
+ paddingLeft: "14px"
8962
+ }),
8963
+ grandchildActive: (c) => ({
8964
+ ...textStyle(c),
8965
+ borderLeft: `2px solid ${c}`,
8966
+ paddingLeft: "10px"
8967
+ })
8968
+ },
8969
+ "system-light": {
8970
+ itemActive: (c) => ({
8971
+ ...tintedStyle(c),
8972
+ borderLeft: `3px solid ${c}`,
8973
+ paddingLeft: "9px"
8974
+ }),
8975
+ subItemActive: textStyle,
8976
+ childActive: (c) => ({
8977
+ ...tintedStyle(c),
8978
+ borderLeft: `2px solid ${c}`,
8979
+ paddingLeft: "14px"
8980
+ }),
8981
+ grandchildActive: (c) => ({
8982
+ ...tintedStyle(c),
8983
+ borderLeft: `2px solid ${c}`,
8984
+ paddingLeft: "10px"
8985
+ })
8986
+ }
8987
+ };
8651
8988
  function Sidebar(props) {
8652
8989
  const navigate = reactRouter.useNavigate();
8653
- const { isOpen: isOpen2, onClose, menuSections, header, className, showCollapseButton = false } = props;
8990
+ const {
8991
+ onClose,
8992
+ menuSections,
8993
+ header,
8994
+ footer,
8995
+ className,
8996
+ showCollapseButton = false,
8997
+ variant = "light",
8998
+ primaryColor
8999
+ } = props;
8654
9000
  const { pathname } = reactRouter.useLocation();
8655
9001
  const [isCollapsed, setIsCollapsed] = React6.useState(false);
8656
- const [isContentVisible, setIsContentVisible] = React6.useState(true);
9002
+ const [overflowVisible, setOverflowVisible] = React6.useState(true);
8657
9003
  const [expandedItems, setExpandedItems] = React6.useState(/* @__PURE__ */ new Set());
8658
9004
  const [expandedSubItems, setExpandedSubItems] = React6.useState(/* @__PURE__ */ new Set());
8659
9005
  React6.useEffect(() => {
8660
- if (isCollapsed) return;
8661
- const timer = setTimeout(() => setIsContentVisible(true), 300);
9006
+ if (isCollapsed) {
9007
+ setOverflowVisible(false);
9008
+ return;
9009
+ }
9010
+ const timer = setTimeout(() => setOverflowVisible(true), 300);
8662
9011
  return () => clearTimeout(timer);
8663
9012
  }, [isCollapsed]);
9013
+ const s = VARIANT_STYLES2[variant];
9014
+ const applier = ACCENT_APPLIERS[variant];
8664
9015
  React6.useEffect(() => {
8665
9016
  menuSections.forEach((section) => {
8666
9017
  section.items.forEach((item) => {
@@ -8711,167 +9062,186 @@ function Sidebar(props) {
8711
9062
  window.open(path, "_blank", "noopener,noreferrer");
8712
9063
  } else if (path !== "") {
8713
9064
  navigate(path);
8714
- onClose();
9065
+ onClose?.();
8715
9066
  }
8716
9067
  };
8717
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8718
- isOpen2 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 bg-black/10 bg-opacity-50 z-40 lg:hidden", onClick: onClose }),
8719
- /* @__PURE__ */ jsxRuntime.jsxs(
8720
- "aside",
8721
- {
8722
- className: `
8723
- ${isCollapsed ? "w-11 min-w-11" : "min-w-60 w-62"}
8724
- ${isOpen2 ? "translate-x-0" : "-translate-x-full lg:translate-x-0"}
8725
- 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
8726
- transition-transform duration-300 ease-in-out
8727
- ${className ?? ""}
8728
- `,
8729
- children: [
8730
- showCollapseButton && /* @__PURE__ */ jsxRuntime.jsx(
8731
- "button",
8732
- {
8733
- onClick: () => {
8734
- if (!isCollapsed) setIsContentVisible(false);
8735
- setIsCollapsed((prev) => !prev);
8736
- },
8737
- 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",
8738
- children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightClose, { size: 18, color: "var(--color-sub-darkgray)" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeftClose, { size: 18, color: "var(--color-sub-darkgray)" })
8739
- }
8740
- ),
8741
- isContentVisible && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-6 pl-6 pr-4", children: [
8742
- /* @__PURE__ */ jsxRuntime.jsx(
8743
- "button",
8744
- {
8745
- onClick: onClose,
8746
- className: "lg:hidden absolute top-4 right-4 p-2 hover:bg-gray-100 rounded-lg transition-colors text-2xl leading-none",
8747
- "aria-label": "Close menu",
8748
- children: "x"
8749
- }
8750
- ),
8751
- header && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-10 mt-2", children: header }),
8752
- /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "space-y-6", children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8753
- section.title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold text-gray-500 tracking-wider mb-3", children: section.title }),
8754
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8755
- /* @__PURE__ */ jsxRuntime.jsxs(
8756
- "button",
8757
- {
8758
- onClick: () => {
8759
- if (item.children) {
8760
- toggleExpand(item.label);
8761
- } else if (item.path) {
8762
- handleItemClick(item.path);
8763
- }
8764
- },
8765
- className: `
8766
- w-full text-left flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors
8767
- ${!item.children && pathname === item.path ? "bg-blue-50 text-blue-600" : "text-gray-700 hover:bg-gray-100"}
8768
- cursor-pointer
8769
- `,
8770
- children: [
8771
- /* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: "w-4 h-4 flex-shrink-0" }),
8772
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
8773
- item.children && /* @__PURE__ */ jsxRuntime.jsx(
8774
- "svg",
8775
- {
8776
- className: `w-4 h-4 transition-transform ${expandedItems.has(item.label) ? "rotate-90" : ""}`,
8777
- fill: "none",
8778
- stroke: "currentColor",
8779
- viewBox: "0 0 24 24",
8780
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
8781
- }
8782
- ),
8783
- item.path?.includes("https") && /* @__PURE__ */ jsxRuntime.jsx(
8784
- "svg",
8785
- {
8786
- className: "w-4 h-4 flex-shrink-0 text-gray-400",
8787
- fill: "none",
8788
- stroke: "currentColor",
8789
- viewBox: "0 0 24 24",
8790
- children: /* @__PURE__ */ jsxRuntime.jsx(
8791
- "path",
9068
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9069
+ "aside",
9070
+ {
9071
+ className: `
9072
+ ${isCollapsed ? "w-11 min-w-11" : "min-w-60 w-62"}
9073
+ transition-[width,min-width] duration-300 ease-in-out
9074
+ relative h-screen shrink-0 overflow-x-hidden flex flex-col
9075
+ ${s.aside}
9076
+ ${className ?? ""}
9077
+ `,
9078
+ children: [
9079
+ showCollapseButton && /* @__PURE__ */ jsxRuntime.jsx(
9080
+ "button",
9081
+ {
9082
+ onClick: () => setIsCollapsed((prev) => !prev),
9083
+ 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}`,
9084
+ children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
9085
+ }
9086
+ ),
9087
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 min-h-0 hide-scrollbar ${overflowVisible ? "overflow-y-auto" : "overflow-hidden"}`, children: /* @__PURE__ */ jsxRuntime.jsxs(
9088
+ "div",
9089
+ {
9090
+ className: `transition-opacity duration-200 ease-in-out ${isCollapsed ? "opacity-0 pointer-events-none select-none" : "opacity-100"} ${variant === "system-dark" || variant === "system-light" ? "pb-6" : "px-4 pb-6"}`,
9091
+ style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9092
+ children: [
9093
+ header && header,
9094
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { className: `space-y-6 ${variant === "system-dark" || variant === "system-light" ? "px-1" : ""}`, children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9095
+ section.title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s.sectionTitle, children: section.title }),
9096
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: section.items.map((item) => {
9097
+ const isActive = !item.children && pathname === item.path;
9098
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9099
+ /* @__PURE__ */ jsxRuntime.jsxs(
9100
+ "button",
9101
+ {
9102
+ onClick: () => {
9103
+ if (item.children) {
9104
+ toggleExpand(item.label);
9105
+ } else if (item.path) {
9106
+ handleItemClick(item.path);
9107
+ }
9108
+ },
9109
+ className: `
9110
+ w-full text-left flex items-center gap-2 px-3 ${s.itemPy} ${s.rounded} ${s.itemTextSize} ${s.itemFont} transition-colors cursor-pointer
9111
+ ${isActive ? s.itemActive : s.itemInactive}
9112
+ `,
9113
+ style: {
9114
+ ...isActive ? s.activeItemStyle : {},
9115
+ ...isActive && primaryColor ? applier.itemActive(primaryColor) : {}
9116
+ },
9117
+ children: [
9118
+ /* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: s.iconClass }),
9119
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
9120
+ item.children && /* @__PURE__ */ jsxRuntime.jsx(
9121
+ "svg",
9122
+ {
9123
+ className: `w-4 h-4 transition-transform ${expandedItems.has(item.label) ? "rotate-90" : ""}`,
9124
+ fill: "none",
9125
+ stroke: "currentColor",
9126
+ viewBox: "0 0 24 24",
9127
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" })
9128
+ }
9129
+ ),
9130
+ item.path?.includes("https") && /* @__PURE__ */ jsxRuntime.jsx(
9131
+ "svg",
8792
9132
  {
8793
- strokeLinecap: "round",
8794
- strokeLinejoin: "round",
8795
- strokeWidth: 2,
8796
- d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
9133
+ className: "w-4 h-4 flex-shrink-0 opacity-50",
9134
+ fill: "none",
9135
+ stroke: "currentColor",
9136
+ viewBox: "0 0 24 24",
9137
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9138
+ "path",
9139
+ {
9140
+ strokeLinecap: "round",
9141
+ strokeLinejoin: "round",
9142
+ strokeWidth: 2,
9143
+ d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
9144
+ }
9145
+ )
8797
9146
  }
8798
9147
  )
8799
- }
8800
- )
8801
- ]
8802
- }
8803
- ),
8804
- item.children && expandedItems.has(item.label) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-[25px] mt-1 space-y-1", children: item.children.map((child, childIndex) => {
8805
- if (child.children && child.children.length > 0) {
8806
- const subKey = `${item.label}::${child.label}`;
8807
- const isSubExpanded = expandedSubItems.has(subKey);
8808
- const isSubActive = child.children.some((gc) => gc.path === pathname);
8809
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8810
- /* @__PURE__ */ jsxRuntime.jsxs(
8811
- "button",
8812
- {
8813
- onClick: () => toggleSubExpand(subKey),
8814
- className: `
8815
- w-full text-left flex items-center justify-between px-3 py-1.5 rounded-lg text-sm transition-colors cursor-pointer
8816
- ${isSubActive ? "text-blue-600 font-medium" : "text-gray-600 hover:bg-gray-50 hover:text-gray-900"}
8817
- `,
8818
- children: [
8819
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: child.label }),
8820
- /* @__PURE__ */ jsxRuntime.jsx(
8821
- "svg",
8822
- {
8823
- className: `w-3 h-3 transition-transform ${isSubExpanded ? "rotate-90" : ""}`,
8824
- fill: "none",
8825
- stroke: "currentColor",
8826
- viewBox: "0 0 24 24",
8827
- children: /* @__PURE__ */ jsxRuntime.jsx(
8828
- "path",
9148
+ ]
9149
+ }
9150
+ ),
9151
+ item.children && expandedItems.has(item.label) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `ml-5 mt-0.5 space-y-0.5 border-l ${s.childGroupBorder}`, children: item.children.map((child, childIndex) => {
9152
+ if (child.children && child.children.length > 0) {
9153
+ const subKey = `${item.label}::${child.label}`;
9154
+ const isSubExpanded = expandedSubItems.has(subKey);
9155
+ const isSubActive = child.children.some((gc) => gc.path === pathname);
9156
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9157
+ /* @__PURE__ */ jsxRuntime.jsxs(
9158
+ "button",
9159
+ {
9160
+ onClick: () => toggleSubExpand(subKey),
9161
+ className: `
9162
+ w-full text-left flex items-center justify-between pl-4 pr-3 ${s.childPy} ${s.rounded} ${s.itemTextSize} transition-colors cursor-pointer
9163
+ ${isSubActive ? s.subItemActive : s.subItemInactive}
9164
+ `,
9165
+ style: isSubActive && primaryColor ? applier.subItemActive(primaryColor) : void 0,
9166
+ children: [
9167
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: child.label }),
9168
+ /* @__PURE__ */ jsxRuntime.jsx(
9169
+ "svg",
8829
9170
  {
8830
- strokeLinecap: "round",
8831
- strokeLinejoin: "round",
8832
- strokeWidth: 2,
8833
- d: "M9 5l7 7-7 7"
9171
+ className: `w-3 h-3 transition-transform ${isSubExpanded ? "rotate-90" : ""}`,
9172
+ fill: "none",
9173
+ stroke: "currentColor",
9174
+ viewBox: "0 0 24 24",
9175
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9176
+ "path",
9177
+ {
9178
+ strokeLinecap: "round",
9179
+ strokeLinejoin: "round",
9180
+ strokeWidth: 2,
9181
+ d: "M9 5l7 7-7 7"
9182
+ }
9183
+ )
8834
9184
  }
8835
9185
  )
8836
- }
8837
- )
8838
- ]
8839
- }
8840
- ),
8841
- isSubExpanded && /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
9186
+ ]
9187
+ }
9188
+ ),
9189
+ isSubExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-3 mt-0.5 space-y-0.5 pl-2", children: child.children.map((grandchild) => {
9190
+ const isGrandchildActive = pathname === grandchild.path;
9191
+ return /* @__PURE__ */ jsxRuntime.jsx(
9192
+ "button",
9193
+ {
9194
+ onClick: () => handleItemClick(grandchild.path),
9195
+ className: `
9196
+ w-full text-left px-3 ${s.grandchildPy} ${s.rounded} ${s.grandchildTextSize} transition-colors cursor-pointer
9197
+ ${isGrandchildActive ? s.grandchildActive : s.grandchildInactive}
9198
+ `,
9199
+ style: {
9200
+ ...isGrandchildActive ? s.activeGrandchildStyle : {},
9201
+ ...isGrandchildActive && primaryColor ? applier.grandchildActive(primaryColor) : {}
9202
+ },
9203
+ children: grandchild.label
9204
+ },
9205
+ grandchild.path
9206
+ );
9207
+ }) })
9208
+ ] }, child.label);
9209
+ }
9210
+ const isChildActive = pathname === child.path;
9211
+ return /* @__PURE__ */ jsxRuntime.jsx(
8842
9212
  "button",
8843
9213
  {
8844
- onClick: () => handleItemClick(grandchild.path),
9214
+ onClick: () => handleItemClick(child.path ?? ""),
8845
9215
  className: `
8846
- w-full text-left px-3 py-1 rounded-lg text-sm transition-colors cursor-pointer
8847
- ${pathname === grandchild.path ? "text-blue-600 font-medium" : "text-gray-500 hover:bg-gray-50 hover:text-gray-900"}
8848
- `,
8849
- children: grandchild.label
9216
+ w-full text-left pl-4 pr-3 ${s.childPy} ${s.rounded} ${s.itemTextSize} transition-colors cursor-pointer
9217
+ ${isChildActive ? s.childActive : s.childInactive}
9218
+ `,
9219
+ style: {
9220
+ ...isChildActive ? s.activeChildStyle : {},
9221
+ ...isChildActive && primaryColor ? applier.childActive(primaryColor) : {}
9222
+ },
9223
+ children: child.label
8850
9224
  },
8851
- grandchild.path
8852
- )) })
8853
- ] }, child.label);
8854
- }
8855
- return /* @__PURE__ */ jsxRuntime.jsx(
8856
- "button",
8857
- {
8858
- onClick: () => handleItemClick(child.path ?? ""),
8859
- className: `
8860
- w-full text-left px-3 py-1.5 rounded-lg text-sm transition-colors cursor-pointer
8861
- ${pathname === child.path ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-600 hover:bg-gray-50 hover:text-gray-900"}
8862
- `,
8863
- children: child.label
8864
- },
8865
- childIndex
8866
- );
9225
+ childIndex
9226
+ );
9227
+ }) })
9228
+ ] }, item.label);
8867
9229
  }) })
8868
- ] }, item.label)) })
8869
- ] }, section.title ?? sectionIndex)) })
8870
- ] })
8871
- ]
8872
- }
8873
- )
8874
- ] });
9230
+ ] }, section.title ?? sectionIndex)) })
9231
+ ]
9232
+ }
9233
+ ) }),
9234
+ footer && /* @__PURE__ */ jsxRuntime.jsx(
9235
+ "div",
9236
+ {
9237
+ className: `flex-shrink-0 transition-opacity duration-200 ease-in-out ${isCollapsed ? "opacity-0 pointer-events-none select-none" : "opacity-100"} ${s.footerBorder}`,
9238
+ style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9239
+ children: footer
9240
+ }
9241
+ )
9242
+ ]
9243
+ }
9244
+ );
8875
9245
  }
8876
9246
  function useDetailController(params = {}) {
8877
9247
  const { mode: controlledMode, onModeChange } = params;
@@ -9168,10 +9538,7 @@ function DetailModalFrame(props) {
9168
9538
  const isEditMode = controller.mode === "edit";
9169
9539
  const canEdit = Boolean(editSchema && (editFields || renderEditBody));
9170
9540
  return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { isOpen: open, onClose: handleClose, contentClassName: cn("max-w-2xl", contentClassName), children: [
9171
- /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { className: "flex flex-row items-center justify-between", children: [
9172
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold text-gray-900", children: title }),
9173
- !isEditMode && canEdit && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", size: "sm", onClick: handleEdit, children: "\uC218\uC815" })
9174
- ] }),
9541
+ /* @__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 }) }),
9175
9542
  /* @__PURE__ */ jsxRuntime.jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
9176
9543
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
9177
9544
  DetailContent,
@@ -9189,10 +9556,11 @@ function DetailModalFrame(props) {
9189
9556
  ) }),
9190
9557
  renderExtraContent?.({ isEditMode })
9191
9558
  ] }),
9192
- /* @__PURE__ */ jsxRuntime.jsx(ModalFooter, { className: "flex justify-end gap-2", children: isEditMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9559
+ /* @__PURE__ */ jsxRuntime.jsx(ModalFooter, { className: "flex justify-end", children: isEditMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9193
9560
  /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: handleCancelEdit, disabled: controller.isSaving, children: "\uCDE8\uC18C" }),
9194
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", form: controller.formId, variant: "save", disabled: controller.isSaving, children: controller.isSaving ? "\uC800\uC7A5 \uC911..." : "\uC800\uC7A5" })
9561
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", form: controller.formId, variant: "save", disabled: controller.isSaving, children: "\uC800\uC7A5" })
9195
9562
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9563
+ canEdit && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: handleEdit, children: "\uC218\uC815" }),
9196
9564
  renderFooterExtra,
9197
9565
  /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: handleClose, children: "\uB2EB\uAE30" })
9198
9566
  ] }) })