@farmzone/fz-react-ui 1.0.3 → 1.0.5

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
  },
@@ -3396,8 +3397,7 @@ function ModalContent(props) {
3396
3397
  {
3397
3398
  ref,
3398
3399
  className: cn(
3399
- "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",
3400
- "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",
3401
3401
  className
3402
3402
  ),
3403
3403
  style: zIndex !== void 0 ? { zIndex } : void 0,
@@ -3408,7 +3408,7 @@ function ModalContent(props) {
3408
3408
  );
3409
3409
  }
3410
3410
  function ModalOverlay(props) {
3411
- const { isOpen: isOpen2, onClose, className, closeOnOverlayClick = true, zIndex } = props;
3411
+ const { ref, isOpen: isOpen2, onClose, className, closeOnOverlayClick = true, zIndex } = props;
3412
3412
  if (!isOpen2) return null;
3413
3413
  const handleOverlayClick = (e) => {
3414
3414
  if (closeOnOverlayClick && e.target === e.currentTarget) {
@@ -3418,9 +3418,10 @@ function ModalOverlay(props) {
3418
3418
  return /* @__PURE__ */ jsxRuntime.jsx(
3419
3419
  "div",
3420
3420
  {
3421
+ ref,
3421
3422
  className: cn(
3422
3423
  "fixed inset-0 z-54 bg-black/50",
3423
- "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",
3424
3425
  className
3425
3426
  ),
3426
3427
  style: zIndex !== void 0 ? { zIndex } : void 0,
@@ -3522,7 +3523,7 @@ function Modal(props) {
3522
3523
  } = props;
3523
3524
  const idRef = React6.useRef(/* @__PURE__ */ Symbol("modal"));
3524
3525
  const [depth, setDepth] = React6.useState(0);
3525
- React6.useEffect(() => {
3526
+ React6.useLayoutEffect(() => {
3526
3527
  if (!isOpen2) return;
3527
3528
  const id = idRef.current;
3528
3529
  const d = modalStack.push(id);
@@ -3559,12 +3560,22 @@ function Modal(props) {
3559
3560
  {
3560
3561
  isOpen: isOpen2,
3561
3562
  onClose,
3562
- className: overlayClassName,
3563
+ className: cn(overlayClassName, depth > 1 && "bg-black/20"),
3563
3564
  closeOnOverlayClick,
3564
3565
  zIndex: overlayZ
3565
3566
  }
3566
3567
  ),
3567
- /* @__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
+ )
3568
3579
  ] });
3569
3580
  }
3570
3581
  function ConfirmModal(props) {
@@ -4065,7 +4076,7 @@ function TableHeader(props) {
4065
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" : "";
4066
4077
  if (column.align === "left") {
4067
4078
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex item-center w-full", children: [
4068
- /* @__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 }) }),
4069
4080
  column.sortable && /* @__PURE__ */ jsxRuntime.jsx(
4070
4081
  "div",
4071
4082
  {
@@ -4096,7 +4107,7 @@ function TableHeader(props) {
4096
4107
  children: renderSortIcon(column.key)
4097
4108
  }
4098
4109
  ),
4099
- /* @__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 }) })
4100
4111
  ] });
4101
4112
  }
4102
4113
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-1.5 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title });
@@ -4467,7 +4478,7 @@ function SkeletonTd(props) {
4467
4478
  return /* @__PURE__ */ jsxRuntime.jsx(
4468
4479
  "td",
4469
4480
  {
4470
- 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`,
4471
4482
  style: {
4472
4483
  width: col.width,
4473
4484
  minWidth: col.minWidth || col.width,
@@ -4539,7 +4550,7 @@ function TableCellContent(props) {
4539
4550
  "div",
4540
4551
  {
4541
4552
  ref: textRef,
4542
- 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"}`,
4543
4554
  style: { textAlign },
4544
4555
  onClick: onCellClick,
4545
4556
  children: shouldShowTooltip ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip2, { content: tooltipText, position: "bottom", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: cellContent }) }) : cellContent
@@ -5008,7 +5019,7 @@ function Table(props) {
5008
5019
  id: `${col.key}-body`,
5009
5020
  "data-row-cell": "true",
5010
5021
  "data-col-key": col.key,
5011
- 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-3"} 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`,
5012
5023
  style: {
5013
5024
  width,
5014
5025
  minWidth: minWidth || width,
@@ -5025,7 +5036,7 @@ function Table(props) {
5025
5036
  tooltipText: String(record[col.key] ?? ""),
5026
5037
  align: align ?? "",
5027
5038
  tooltipConfig: col.key === "__checkbox__" ? false : tooltipConfig,
5028
- onCellClick: col.key !== "__checkbox__" ? () => onRowClickRef.current?.(record, rowIdx) : void 0
5039
+ onCellClick: col.key !== "__checkbox__" && onRowClickRef.current ? () => onRowClickRef.current?.(record, rowIdx) : void 0
5029
5040
  }
5030
5041
  ) })
5031
5042
  },
@@ -5100,7 +5111,7 @@ function Table(props) {
5100
5111
  const rest = baseRows.filter((row) => !effectiveRowOrder.includes(String(getRowKey(row.original, row.index))));
5101
5112
  return [...ordered, ...rest];
5102
5113
  }, [baseRows, effectiveRowOrder, getRowKey]);
5103
- 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: [
5104
5115
  /* @__PURE__ */ jsxRuntime.jsx(
5105
5116
  "div",
5106
5117
  {
@@ -5124,7 +5135,7 @@ function Table(props) {
5124
5135
  isColumnDraggable
5125
5136
  }
5126
5137
  ),
5127
- /* @__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: [
5128
5139
  leadingPinnedCols.map((col, idx) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonTd, { col, showSquare: idx === 0 && !!checkboxInfo }, `leading-${idx}`)),
5129
5140
  leftColspan > 0 && /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: leftColspan, style: { padding: 0, border: "none" } }),
5130
5141
  virtualItems.map((vc) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonTd, { col: groupCols[vc.index] }, `group-${vc.index}`)),
@@ -6136,14 +6147,53 @@ function resolveValueColSpan(colspan) {
6136
6147
  const span = colspan ?? 10;
6137
6148
  return COL_SPAN_CLASS[span] ?? COL_SPAN_CLASS[10];
6138
6149
  }
6150
+ var THREE_DIGIT_AREA_CODES = /* @__PURE__ */ new Set([
6151
+ "031",
6152
+ "032",
6153
+ "033",
6154
+ "041",
6155
+ "042",
6156
+ "043",
6157
+ "051",
6158
+ "052",
6159
+ "053",
6160
+ "054",
6161
+ "055",
6162
+ "061",
6163
+ "062",
6164
+ "063"
6165
+ ]);
6139
6166
  function formatPhoneNumber(value) {
6140
- const numbers = value.replace(/\D/g, "");
6141
- if (numbers.length <= 3) return numbers;
6142
- if (numbers.length <= 7) return `${numbers.slice(0, 3)}-${numbers.slice(3)}`;
6143
- if (numbers.length <= 11) {
6144
- return `${numbers.slice(0, 3)}-${numbers.slice(3, 7)}-${numbers.slice(7)}`;
6167
+ let digits = value.replace(/\D/g, "");
6168
+ if (digits.startsWith("02")) {
6169
+ if (digits.length > 2 && digits.length <= 6) {
6170
+ return `${digits.slice(0, 2)}-${digits.slice(2)}`;
6171
+ }
6172
+ if (digits.length > 6) {
6173
+ return `${digits.slice(0, 2)}-${digits.slice(2, 6)}-${digits.slice(6)}`;
6174
+ }
6175
+ } else if (THREE_DIGIT_AREA_CODES.has(digits.slice(0, 3))) {
6176
+ if (digits.length > 3 && digits.length <= 6) {
6177
+ return `${digits.slice(0, 3)}-${digits.slice(3)}`;
6178
+ }
6179
+ if (digits.length > 6) {
6180
+ return `${digits.slice(0, 3)}-${digits.slice(3, 6)}-${digits.slice(6)}`;
6181
+ }
6182
+ } else {
6183
+ if (digits.length > 3 && digits.length <= 7) {
6184
+ return `${digits.slice(0, 3)}-${digits.slice(3)}`;
6185
+ }
6186
+ if (digits.length > 7) {
6187
+ return `${digits.slice(0, 3)}-${digits.slice(3, 7)}-${digits.slice(7)}`;
6188
+ }
6189
+ }
6190
+ return digits;
6191
+ }
6192
+ function resolvePhoneMaxLength(formattedValue) {
6193
+ if (formattedValue.startsWith("02") || THREE_DIGIT_AREA_CODES.has(formattedValue.slice(0, 3))) {
6194
+ return 12;
6145
6195
  }
6146
- return `${numbers.slice(0, 3)}-${numbers.slice(3, 7)}-${numbers.slice(7, 11)}`;
6196
+ return 13;
6147
6197
  }
6148
6198
  function formatNumberWithCommas(value) {
6149
6199
  const numStr = String(value).replace(/,/g, "");
@@ -6838,7 +6888,8 @@ function InputField(props) {
6838
6888
  maxLength,
6839
6889
  className = "",
6840
6890
  type = "input",
6841
- numbersOnly = false
6891
+ numbersOnly = false,
6892
+ autoComplete
6842
6893
  } = config;
6843
6894
  const inputType = type === "email" ? "email" : type === "password" ? "password" : "text";
6844
6895
  if (readOnly) {
@@ -6863,6 +6914,7 @@ function InputField(props) {
6863
6914
  maxLength,
6864
6915
  status: "default",
6865
6916
  className: formControlClass(hasError),
6917
+ autoComplete,
6866
6918
  bare: true,
6867
6919
  onChange: handleChange
6868
6920
  }
@@ -6965,11 +7017,13 @@ function PhoneField(props) {
6965
7017
  hasError = false
6966
7018
  } = props;
6967
7019
  const { placeholder = "010-0000-0000", disabled = false, readOnly = false, className = "" } = config;
7020
+ const phoneValue = String(value ?? "");
7021
+ const phoneMaxLength = resolvePhoneMaxLength(phoneValue);
6968
7022
  const handleChange = (e) => {
6969
7023
  onChange(formatPhoneNumber(e.target.value));
6970
7024
  };
6971
7025
  if (readOnly) {
6972
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: fieldControlWrapClass(className), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: FIELD_READONLY_TEXT_CLASS, children: String(value ?? "") || "\u2014" }) });
7026
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: fieldControlWrapClass(className), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: FIELD_READONLY_TEXT_CLASS, children: phoneValue || "\u2014" }) });
6973
7027
  }
6974
7028
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: fieldControlWrapClass(className), children: /* @__PURE__ */ jsxRuntime.jsx(
6975
7029
  Input2,
@@ -6977,12 +7031,12 @@ function PhoneField(props) {
6977
7031
  name,
6978
7032
  ref,
6979
7033
  onBlur,
6980
- value: String(value ?? ""),
7034
+ value: phoneValue,
6981
7035
  type: "text",
6982
7036
  placeholder,
6983
7037
  disabled,
6984
7038
  readOnly,
6985
- maxLength: 13,
7039
+ maxLength: phoneMaxLength,
6986
7040
  status: "default",
6987
7041
  className: formControlClass(hasError),
6988
7042
  bare: true,
@@ -7568,7 +7622,8 @@ function SubmitFormRoot(props) {
7568
7622
  className = "",
7569
7623
  formClassName,
7570
7624
  gridClassName = "grid-cols-12",
7571
- mode = "onSubmit"
7625
+ mode = "onSubmit",
7626
+ autoComplete
7572
7627
  } = props;
7573
7628
  const methods = reactHookForm.useForm({
7574
7629
  resolver: zod.zodResolver(schema),
@@ -7591,6 +7646,7 @@ function SubmitFormRoot(props) {
7591
7646
  id: formId,
7592
7647
  onSubmit: handleSubmit,
7593
7648
  className: cn2(SUBMIT_FORM_CLASS, formClassName, className),
7649
+ autoComplete,
7594
7650
  noValidate: true,
7595
7651
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid ${gridClassName} items-stretch gap-0`, children })
7596
7652
  }
@@ -7618,7 +7674,8 @@ function PageFilter(props) {
7618
7674
  colGap = 0,
7619
7675
  submitButtonText = "\uAC80\uC0C9",
7620
7676
  resetButtonText = "\uCD08\uAE30\uD654",
7621
- values
7677
+ values,
7678
+ primaryColor
7622
7679
  } = props;
7623
7680
  const [localValues, setLocalValues] = React6.useState(values);
7624
7681
  const initialValuesRef = React6.useRef(values);
@@ -7676,6 +7733,7 @@ function PageFilter(props) {
7676
7733
  onChange: handleSelectChange(optionKey),
7677
7734
  options: option.options,
7678
7735
  placeholder: "\uC120\uD0DD",
7736
+ canReset: true,
7679
7737
  containerClassName: option.containerClassName ?? "w-30"
7680
7738
  }
7681
7739
  ) }, String(optionKey));
@@ -7728,16 +7786,20 @@ function PageFilter(props) {
7728
7786
  "div",
7729
7787
  {
7730
7788
  className: cn(
7731
- "flex flex-col gap-3 bg-white py-3 px-5 border-t-main border-t-1 shadow-page-filter",
7789
+ "flex flex-col gap-3 bg-white py-3 px-5 border-t-main border-t-1 shadow-panel",
7732
7790
  containerClassName
7733
7791
  ),
7734
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: [
7735
- 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("_"))),
7736
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-2 bottom-2 flex justify-end gap-2 pt-2", children: [
7737
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7738
- onReset && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7739
- ] })
7740
- ] })
7792
+ style: primaryColor ? { borderTopColor: primaryColor } : void 0,
7793
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: rows.map((row, ix) => {
7794
+ const isLastRow = rows.length - 1 === ix;
7795
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row min-h-12", children: [
7796
+ row.options.map((option, index) => renderFilterOption(option, rowGap, index)),
7797
+ isLastRow && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-4 flex flex-row items-center gap-2", children: [
7798
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7799
+ onReset && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7800
+ ] })
7801
+ ] }, row.options.map((opt) => String(opt.key)).join("_"));
7802
+ }) })
7741
7803
  }
7742
7804
  );
7743
7805
  }
@@ -7749,7 +7811,9 @@ var VARIANT_STYLES = {
7749
7811
  activeText: "font-semibold text-gray-800",
7750
7812
  inactiveText: "font-normal",
7751
7813
  indicator: "bg-blue-500",
7752
- closeBtn: "hover:bg-gray-300/60",
7814
+ closeBtn: "rounded hover:bg-gray-300/60",
7815
+ closeBtnWH: "w-3.5 h-3.5",
7816
+ closeBtnSize: 10,
7753
7817
  plusBtnArea: "border-l border-gray-100 bg-white",
7754
7818
  plusBtn: "text-gray-400 hover:text-gray-600 hover:bg-gray-100",
7755
7819
  fadeOpacity: 0.12,
@@ -7766,7 +7830,9 @@ var VARIANT_STYLES = {
7766
7830
  activeText: "font-semibold text-white",
7767
7831
  inactiveText: "font-normal",
7768
7832
  indicator: "bg-indigo-400",
7769
- closeBtn: "hover:bg-gray-600/60",
7833
+ closeBtn: "rounded hover:bg-gray-600/60",
7834
+ closeBtnWH: "w-3.5 h-3.5",
7835
+ closeBtnSize: 10,
7770
7836
  plusBtnArea: "border-l border-gray-700 bg-gray-900",
7771
7837
  plusBtn: "text-gray-500 hover:text-gray-300 hover:bg-gray-700",
7772
7838
  fadeOpacity: 0.4,
@@ -7779,11 +7845,13 @@ var VARIANT_STYLES = {
7779
7845
  "system-light": {
7780
7846
  container: "bg-gray-200 border-b border-gray-300",
7781
7847
  activeTab: "bg-white border-gray-300 text-slate-800 shadow-sm",
7782
- inactiveTab: "bg-transparent border-gray-300/80 text-slate-500 hover:text-slate-700 hover:bg-gray-200 hover:border-gray-300",
7848
+ inactiveTab: "bg-transparent border-gray-300/80 text-slate-500 hover:text-slate-700 hover:bg-[#efefef] hover:border-gray-300",
7783
7849
  activeText: "font-semibold text-slate-800",
7784
7850
  inactiveText: "font-medium",
7785
7851
  indicator: "bg-[#2b2b2b]",
7786
- closeBtn: "hover:bg-gray-300",
7852
+ closeBtn: "ml-auto text-slate-400 hover:text-slate-700",
7853
+ closeBtnWH: "w-4 h-4",
7854
+ closeBtnSize: 13,
7787
7855
  plusBtnArea: "border-l border-gray-300 bg-gray-200",
7788
7856
  plusBtn: "text-slate-400 hover:text-slate-600 hover:bg-gray-300",
7789
7857
  fadeOpacity: 0.15,
@@ -7800,7 +7868,9 @@ var VARIANT_STYLES = {
7800
7868
  activeText: "font-semibold text-slate-100",
7801
7869
  inactiveText: "font-medium",
7802
7870
  indicator: "bg-indigo-400",
7803
- closeBtn: "hover:bg-slate-600/60",
7871
+ closeBtn: "ml-auto text-slate-500 hover:text-slate-200",
7872
+ closeBtnWH: "w-4 h-4",
7873
+ closeBtnSize: 13,
7804
7874
  plusBtnArea: "border-l border-slate-700 bg-slate-900",
7805
7875
  plusBtn: "text-slate-400 hover:text-slate-200 hover:bg-slate-700",
7806
7876
  fadeOpacity: 0.45,
@@ -7953,12 +8023,12 @@ function MultiTabBar(props) {
7953
8023
  onTabClose(tab.id);
7954
8024
  },
7955
8025
  className: `
7956
- flex-shrink-0 w-3.5 h-3.5 flex items-center justify-center
7957
- rounded transition-all duration-100 cursor-pointer
8026
+ flex-shrink-0 ${s.closeBtnWH} flex items-center justify-center
8027
+ transition-all duration-100 cursor-pointer
7958
8028
  ${s.closeBtn}
7959
8029
  ${isActive ? "opacity-100" : "opacity-40 group-hover:opacity-60"}
7960
8030
  `,
7961
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 10, strokeWidth: 2.5 })
8031
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: s.closeBtnSize, strokeWidth: 2.5 })
7962
8032
  }
7963
8033
  )
7964
8034
  ]
@@ -8788,7 +8858,8 @@ var VARIANT_STYLES2 = {
8788
8858
  iconClass: "w-4 h-4 flex-shrink-0",
8789
8859
  activeItemStyle: {},
8790
8860
  activeChildStyle: {},
8791
- activeGrandchildStyle: {}
8861
+ activeGrandchildStyle: {},
8862
+ footerBorder: "border-t border-gray-200"
8792
8863
  },
8793
8864
  dark: {
8794
8865
  aside: "bg-gray-900 border-r border-gray-700",
@@ -8814,7 +8885,8 @@ var VARIANT_STYLES2 = {
8814
8885
  iconClass: "w-4 h-4 flex-shrink-0",
8815
8886
  activeItemStyle: {},
8816
8887
  activeChildStyle: {},
8817
- activeGrandchildStyle: {}
8888
+ activeGrandchildStyle: {},
8889
+ footerBorder: "border-t border-gray-700"
8818
8890
  },
8819
8891
  "system-dark": {
8820
8892
  aside: "bg-slate-900 border-r border-slate-700",
@@ -8840,7 +8912,8 @@ var VARIANT_STYLES2 = {
8840
8912
  iconClass: "w-4.5 h-4.5 flex-shrink-0",
8841
8913
  activeItemStyle: { borderLeft: "3px solid #818cf8", paddingLeft: "9px" },
8842
8914
  activeChildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "14px" },
8843
- activeGrandchildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "10px" }
8915
+ activeGrandchildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "10px" },
8916
+ footerBorder: "border-t border-slate-700"
8844
8917
  },
8845
8918
  "system-light": {
8846
8919
  aside: "bg-gray-50 border-r border-gray-200",
@@ -8881,7 +8954,8 @@ var VARIANT_STYLES2 = {
8881
8954
  backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8882
8955
  borderLeft: "2px solid #2b2b2b",
8883
8956
  paddingLeft: "10px"
8884
- }
8957
+ },
8958
+ footerBorder: "border-t border-gray-200"
8885
8959
  }
8886
8960
  };
8887
8961
  function tintedStyle(color) {
@@ -8958,6 +9032,7 @@ function Sidebar(props) {
8958
9032
  onClose,
8959
9033
  menuSections,
8960
9034
  header,
9035
+ footer,
8961
9036
  className,
8962
9037
  showCollapseButton = false,
8963
9038
  variant = "light",
@@ -8965,8 +9040,17 @@ function Sidebar(props) {
8965
9040
  } = props;
8966
9041
  const { pathname } = reactRouter.useLocation();
8967
9042
  const [isCollapsed, setIsCollapsed] = React6.useState(false);
9043
+ const [overflowVisible, setOverflowVisible] = React6.useState(true);
8968
9044
  const [expandedItems, setExpandedItems] = React6.useState(/* @__PURE__ */ new Set());
8969
9045
  const [expandedSubItems, setExpandedSubItems] = React6.useState(/* @__PURE__ */ new Set());
9046
+ React6.useEffect(() => {
9047
+ if (isCollapsed) {
9048
+ setOverflowVisible(false);
9049
+ return;
9050
+ }
9051
+ const timer = setTimeout(() => setOverflowVisible(true), 300);
9052
+ return () => clearTimeout(timer);
9053
+ }, [isCollapsed]);
8970
9054
  const s = VARIANT_STYLES2[variant];
8971
9055
  const applier = ACCENT_APPLIERS[variant];
8972
9056
  React6.useEffect(() => {
@@ -9028,7 +9112,7 @@ function Sidebar(props) {
9028
9112
  className: `
9029
9113
  ${isCollapsed ? "w-11 min-w-11" : "min-w-60 w-62"}
9030
9114
  transition-[width,min-width] duration-300 ease-in-out
9031
- hide-scrollbar relative h-screen shrink-0 overflow-y-auto overflow-x-hidden
9115
+ relative h-screen shrink-0 overflow-x-hidden flex flex-col
9032
9116
  ${s.aside}
9033
9117
  ${className ?? ""}
9034
9118
  `,
@@ -9041,14 +9125,14 @@ function Sidebar(props) {
9041
9125
  children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
9042
9126
  }
9043
9127
  ),
9044
- /* @__PURE__ */ jsxRuntime.jsxs(
9128
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 min-h-0 hide-scrollbar ${overflowVisible ? "overflow-y-auto" : "overflow-hidden"}`, children: /* @__PURE__ */ jsxRuntime.jsxs(
9045
9129
  "div",
9046
9130
  {
9047
- 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"}`,
9131
+ 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"}`,
9048
9132
  style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9049
9133
  children: [
9050
- header && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 mt-2", children: header }),
9051
- /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "space-y-6", children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9134
+ header && header,
9135
+ /* @__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: [
9052
9136
  section.title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s.sectionTitle, children: section.title }),
9053
9137
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: section.items.map((item) => {
9054
9138
  const isActive = !item.children && pathname === item.path;
@@ -9187,6 +9271,14 @@ function Sidebar(props) {
9187
9271
  ] }, section.title ?? sectionIndex)) })
9188
9272
  ]
9189
9273
  }
9274
+ ) }),
9275
+ footer && /* @__PURE__ */ jsxRuntime.jsx(
9276
+ "div",
9277
+ {
9278
+ className: `flex-shrink-0 transition-opacity duration-200 ease-in-out ${isCollapsed ? "opacity-0 pointer-events-none select-none" : "opacity-100"} ${s.footerBorder}`,
9279
+ style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9280
+ children: footer
9281
+ }
9190
9282
  )
9191
9283
  ]
9192
9284
  }
@@ -9505,7 +9597,7 @@ function DetailModalFrame(props) {
9505
9597
  ) }),
9506
9598
  renderExtraContent?.({ isEditMode })
9507
9599
  ] }),
9508
- /* @__PURE__ */ jsxRuntime.jsx(ModalFooter, { className: "flex justify-end gap-2", children: isEditMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9600
+ /* @__PURE__ */ jsxRuntime.jsx(ModalFooter, { className: "flex justify-end", children: isEditMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9509
9601
  /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: handleCancelEdit, disabled: controller.isSaving, children: "\uCDE8\uC18C" }),
9510
9602
  /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", form: controller.formId, variant: "save", disabled: controller.isSaving, children: "\uC800\uC7A5" })
9511
9603
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -9790,6 +9882,144 @@ function useScrollToTop(containerId) {
9790
9882
  return scrollToTop;
9791
9883
  }
9792
9884
 
9885
+ // src/hooks/useParams/config/utils.ts
9886
+ function paramsToSearchParams(params) {
9887
+ const searchParams = new URLSearchParams();
9888
+ Object.entries(params).forEach(([key, value]) => {
9889
+ if (value === null || value === void 0) {
9890
+ return;
9891
+ }
9892
+ if (Array.isArray(value)) {
9893
+ value.forEach((item) => searchParams.append(key, String(item)));
9894
+ } else if (value !== "") {
9895
+ searchParams.set(key, String(value));
9896
+ }
9897
+ });
9898
+ return searchParams;
9899
+ }
9900
+ function useParams(initialParams) {
9901
+ if (!initialParams) {
9902
+ throw new Error("initialParams is required");
9903
+ }
9904
+ const [params, setParams] = React6.useState(initialParams);
9905
+ const [localParams, setLocalParams] = React6.useState(initialParams);
9906
+ const [searchParams, setSearchParams] = reactRouter.useSearchParams();
9907
+ const isInitializedRef = React6.useRef(false);
9908
+ const getInitialState = React6.useCallback(() => {
9909
+ const result = { ...initialParams };
9910
+ Object.keys(initialParams).forEach((key) => {
9911
+ const initialValue = initialParams[key];
9912
+ if (Array.isArray(initialValue)) {
9913
+ const urlValue = searchParams.getAll(key);
9914
+ if (urlValue.length > 0) {
9915
+ result[key] = urlValue;
9916
+ }
9917
+ } else {
9918
+ const urlValue = searchParams.get(key);
9919
+ if (urlValue !== null) {
9920
+ if (urlValue === "null") {
9921
+ result[key] = null;
9922
+ } else if (urlValue === "undefined") {
9923
+ result[key] = void 0;
9924
+ } else {
9925
+ result[key] = urlValue;
9926
+ }
9927
+ }
9928
+ }
9929
+ });
9930
+ return result;
9931
+ }, [initialParams, searchParams]);
9932
+ React6.useEffect(() => {
9933
+ if (!isInitializedRef.current) {
9934
+ const initialState = getInitialState();
9935
+ setLocalParams(initialState);
9936
+ setParams(initialState);
9937
+ if (!searchParams.toString()) {
9938
+ const newSearchParams = paramsToSearchParams(initialParams);
9939
+ setSearchParams(newSearchParams, { replace: true });
9940
+ }
9941
+ isInitializedRef.current = true;
9942
+ }
9943
+ }, [getInitialState, initialParams, searchParams, setSearchParams]);
9944
+ const updateLocalParam = React6.useCallback(
9945
+ (key, value) => {
9946
+ setLocalParams((prev) => ({
9947
+ ...prev,
9948
+ [key]: value
9949
+ }));
9950
+ },
9951
+ [setLocalParams]
9952
+ );
9953
+ const updateParams = React6.useCallback(
9954
+ (updatedParams) => {
9955
+ const newParams = {
9956
+ ...params,
9957
+ ...updatedParams
9958
+ };
9959
+ setParams(newParams);
9960
+ setLocalParams(newParams);
9961
+ setSearchParams(paramsToSearchParams(newParams));
9962
+ },
9963
+ [params, setSearchParams]
9964
+ );
9965
+ const updateParam = React6.useCallback(
9966
+ (key, value) => {
9967
+ const newParams = {
9968
+ ...params,
9969
+ [key]: value
9970
+ };
9971
+ setParams(newParams);
9972
+ setLocalParams(newParams);
9973
+ setSearchParams(paramsToSearchParams(newParams));
9974
+ },
9975
+ [params, setSearchParams]
9976
+ );
9977
+ const update = React6.useCallback(() => {
9978
+ const paramsWithResetPage = {
9979
+ ...localParams,
9980
+ page: 0
9981
+ };
9982
+ const newSearchParams = paramsToSearchParams(paramsWithResetPage);
9983
+ setSearchParams(newSearchParams);
9984
+ setParams(paramsWithResetPage);
9985
+ setLocalParams(paramsWithResetPage);
9986
+ }, [localParams, setSearchParams]);
9987
+ const reset = React6.useCallback(() => {
9988
+ setLocalParams(initialParams);
9989
+ setParams(initialParams);
9990
+ const newSearchParams = paramsToSearchParams(initialParams);
9991
+ setSearchParams(newSearchParams);
9992
+ }, [initialParams, setSearchParams]);
9993
+ const handleSortChange = React6.useCallback(
9994
+ (sortKey, sortOrder) => {
9995
+ const newParams = {
9996
+ ...params,
9997
+ sortBy: sortKey,
9998
+ sortOrder
9999
+ };
10000
+ updateParams(newParams);
10001
+ },
10002
+ [updateParams, params]
10003
+ );
10004
+ const sortOption = React6.useMemo(() => {
10005
+ if (!params.sortBy || !params.sortOrder) return void 0;
10006
+ return {
10007
+ sortKey: params.sortBy,
10008
+ sortOrder: params.sortOrder
10009
+ };
10010
+ }, [params.sortBy, params.sortOrder]);
10011
+ return {
10012
+ localParams,
10013
+ params,
10014
+ updateParam,
10015
+ updateLocalParam,
10016
+ update,
10017
+ reset,
10018
+ handleSortChange,
10019
+ sortOption
10020
+ };
10021
+ }
10022
+
9793
10023
  exports.ArrowIcon = ArrowIcon;
9794
10024
  exports.Badge = Badge;
9795
10025
  exports.BaseUploader = BaseUploader;
@@ -9880,6 +10110,7 @@ exports.useDetailController = useDetailController;
9880
10110
  exports.useFilePreviewViewer = useFilePreviewViewer;
9881
10111
  exports.useModal = useModal;
9882
10112
  exports.useMultiTabStore = useMultiTabStore;
10113
+ exports.useParams = useParams;
9883
10114
  exports.useScrollToTop = useScrollToTop;
9884
10115
  exports.useStableImageSrc = useStableImageSrc;
9885
10116
  exports.useToast = useToast;