@farmzone/fz-react-ui 1.0.3 → 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.d.cts CHANGED
@@ -26,7 +26,7 @@ interface BadgeProps {
26
26
  }
27
27
  declare function Badge(props: BadgeProps): react.JSX.Element;
28
28
 
29
- type ButtonVariant = "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "ghost" | "link";
29
+ type ButtonVariant = "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "ghost" | "link" | "metal";
30
30
  type ButtonSize = "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | "link";
31
31
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
32
32
  ref?: Ref<HTMLButtonElement>;
@@ -571,6 +571,7 @@ interface ModalIconHeaderProps {
571
571
  declare function ModalIconHeader(props: ModalIconHeaderProps): react.JSX.Element;
572
572
 
573
573
  interface ModalOverlayProps {
574
+ ref?: Ref<HTMLDivElement>;
574
575
  isOpen: boolean;
575
576
  onClose?: () => void;
576
577
  className?: string;
@@ -890,6 +891,7 @@ interface FormFieldConfig<TFieldValues extends FieldValues = FieldValues> {
890
891
  selectWithInputClassNames?: SelectWithInputFieldClassNames;
891
892
  inputWithButton?: InputWithButtonFieldConfig;
892
893
  onClickInputWithButton?: () => void;
894
+ autoComplete?: string;
893
895
  }
894
896
  interface CustomFieldRenderProps<TFieldValues extends FieldValues = FieldValues> {
895
897
  field: ControllerRenderProps<TFieldValues, Path<TFieldValues>>;
@@ -909,6 +911,7 @@ interface SubmitFormProps<TSchema extends z.ZodTypeAny = z.ZodTypeAny> {
909
911
  * blur 검증은 FormField가 `trigger`로 수동 실행.
910
912
  */
911
913
  mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
914
+ autoComplete?: string;
912
915
  }
913
916
 
914
917
  declare function FormTable<TFieldValues extends FieldValues = FieldValues>(props: FormTableProps<TFieldValues>): react.JSX.Element;
@@ -978,6 +981,7 @@ interface PageFilterProps<P> {
978
981
  submitButtonText?: string;
979
982
  resetButtonText?: string;
980
983
  values: P;
984
+ primaryColor?: string;
981
985
  }
982
986
  declare function PageFilter<P extends Record<keyof P, string>>(props: PageFilterProps<P>): react.JSX.Element;
983
987
 
@@ -1128,6 +1132,7 @@ type SidebarVariant = "light" | "dark" | "system-dark" | "system-light";
1128
1132
  interface SidebarProps {
1129
1133
  menuSections: Array<MenuSection>;
1130
1134
  header?: ReactNode;
1135
+ footer?: ReactNode;
1131
1136
  className?: string;
1132
1137
  showCollapseButton?: boolean;
1133
1138
  onClose?: () => void;
@@ -1331,7 +1336,7 @@ declare function ArrowIcon(props: ArrowIconProps): react.JSX.Element;
1331
1336
 
1332
1337
  declare function cn(...inputs: Array<ClassValue>): string;
1333
1338
  declare const buttonVariants: (props?: ({
1334
- variant?: "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "ghost" | "link" | null | undefined;
1339
+ variant?: "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "metal" | "ghost" | "link" | null | undefined;
1335
1340
  size?: "link" | "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
1336
1341
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1337
1342
  declare const textVariants: (props?: ({
package/dist/index.d.ts CHANGED
@@ -26,7 +26,7 @@ interface BadgeProps {
26
26
  }
27
27
  declare function Badge(props: BadgeProps): react.JSX.Element;
28
28
 
29
- type ButtonVariant = "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "ghost" | "link";
29
+ type ButtonVariant = "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "ghost" | "link" | "metal";
30
30
  type ButtonSize = "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | "link";
31
31
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
32
32
  ref?: Ref<HTMLButtonElement>;
@@ -571,6 +571,7 @@ interface ModalIconHeaderProps {
571
571
  declare function ModalIconHeader(props: ModalIconHeaderProps): react.JSX.Element;
572
572
 
573
573
  interface ModalOverlayProps {
574
+ ref?: Ref<HTMLDivElement>;
574
575
  isOpen: boolean;
575
576
  onClose?: () => void;
576
577
  className?: string;
@@ -890,6 +891,7 @@ interface FormFieldConfig<TFieldValues extends FieldValues = FieldValues> {
890
891
  selectWithInputClassNames?: SelectWithInputFieldClassNames;
891
892
  inputWithButton?: InputWithButtonFieldConfig;
892
893
  onClickInputWithButton?: () => void;
894
+ autoComplete?: string;
893
895
  }
894
896
  interface CustomFieldRenderProps<TFieldValues extends FieldValues = FieldValues> {
895
897
  field: ControllerRenderProps<TFieldValues, Path<TFieldValues>>;
@@ -909,6 +911,7 @@ interface SubmitFormProps<TSchema extends z.ZodTypeAny = z.ZodTypeAny> {
909
911
  * blur 검증은 FormField가 `trigger`로 수동 실행.
910
912
  */
911
913
  mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
914
+ autoComplete?: string;
912
915
  }
913
916
 
914
917
  declare function FormTable<TFieldValues extends FieldValues = FieldValues>(props: FormTableProps<TFieldValues>): react.JSX.Element;
@@ -978,6 +981,7 @@ interface PageFilterProps<P> {
978
981
  submitButtonText?: string;
979
982
  resetButtonText?: string;
980
983
  values: P;
984
+ primaryColor?: string;
981
985
  }
982
986
  declare function PageFilter<P extends Record<keyof P, string>>(props: PageFilterProps<P>): react.JSX.Element;
983
987
 
@@ -1128,6 +1132,7 @@ type SidebarVariant = "light" | "dark" | "system-dark" | "system-light";
1128
1132
  interface SidebarProps {
1129
1133
  menuSections: Array<MenuSection>;
1130
1134
  header?: ReactNode;
1135
+ footer?: ReactNode;
1131
1136
  className?: string;
1132
1137
  showCollapseButton?: boolean;
1133
1138
  onClose?: () => void;
@@ -1331,7 +1336,7 @@ declare function ArrowIcon(props: ArrowIconProps): react.JSX.Element;
1331
1336
 
1332
1337
  declare function cn(...inputs: Array<ClassValue>): string;
1333
1338
  declare const buttonVariants: (props?: ({
1334
- variant?: "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "ghost" | "link" | null | undefined;
1339
+ variant?: "outline" | "save" | "delete" | "reset" | "search" | "file" | "carousel" | "accent" | "metal" | "ghost" | "link" | null | undefined;
1335
1340
  size?: "link" | "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
1336
1341
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1337
1342
  declare const textVariants: (props?: ({
package/dist/index.js CHANGED
@@ -44,9 +44,10 @@ var buttonVariants = cva(
44
44
  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",
45
45
  reset: "bg-white border border-sub-lightgray-2 text-sub-darkgray hover:bg-gray-100 hover:text-black",
46
46
  search: "bg-main-blue border-none text-white hover:bg-main-blue/90",
47
- file: "bg-sub-darkgray text-white hover:bg-sub-darkgray/80",
47
+ file: "bg-btn-file text-white hover:bg-btn-file/90",
48
48
  carousel: "bg-white border border-gray-300 hover:bg-gray-100 hover:text-black rounded-full",
49
49
  accent: "btn-grad text-white rounded-full",
50
+ metal: "btn-metal text-white min-w-22",
50
51
  ghost: "p-1 h-auto rounded-sm bg-transparent hover:bg-sub-lightgray text-sub-darkgray hover:bg-inherit",
51
52
  link: "bg-transparent border-none text-main-blue underline-offset-4 hover:underline h-auto p-0"
52
53
  },
@@ -3362,8 +3363,7 @@ function ModalContent(props) {
3362
3363
  {
3363
3364
  ref,
3364
3365
  className: cn(
3365
- "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",
3366
- "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%]",
3366
+ "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",
3367
3367
  className
3368
3368
  ),
3369
3369
  style: zIndex !== void 0 ? { zIndex } : void 0,
@@ -3374,7 +3374,7 @@ function ModalContent(props) {
3374
3374
  );
3375
3375
  }
3376
3376
  function ModalOverlay(props) {
3377
- const { isOpen: isOpen2, onClose, className, closeOnOverlayClick = true, zIndex } = props;
3377
+ const { ref, isOpen: isOpen2, onClose, className, closeOnOverlayClick = true, zIndex } = props;
3378
3378
  if (!isOpen2) return null;
3379
3379
  const handleOverlayClick = (e) => {
3380
3380
  if (closeOnOverlayClick && e.target === e.currentTarget) {
@@ -3384,9 +3384,10 @@ function ModalOverlay(props) {
3384
3384
  return /* @__PURE__ */ jsx(
3385
3385
  "div",
3386
3386
  {
3387
+ ref,
3387
3388
  className: cn(
3388
3389
  "fixed inset-0 z-54 bg-black/50",
3389
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
3390
+ "animate-in fade-in-0 duration-150",
3390
3391
  className
3391
3392
  ),
3392
3393
  style: zIndex !== void 0 ? { zIndex } : void 0,
@@ -3488,7 +3489,7 @@ function Modal(props) {
3488
3489
  } = props;
3489
3490
  const idRef = useRef(/* @__PURE__ */ Symbol("modal"));
3490
3491
  const [depth, setDepth] = useState(0);
3491
- useEffect(() => {
3492
+ useLayoutEffect(() => {
3492
3493
  if (!isOpen2) return;
3493
3494
  const id = idRef.current;
3494
3495
  const d = modalStack.push(id);
@@ -3525,12 +3526,22 @@ function Modal(props) {
3525
3526
  {
3526
3527
  isOpen: isOpen2,
3527
3528
  onClose,
3528
- className: overlayClassName,
3529
+ className: cn(overlayClassName, depth > 1 && "bg-black/20"),
3529
3530
  closeOnOverlayClick,
3530
3531
  zIndex: overlayZ
3531
3532
  }
3532
3533
  ),
3533
- /* @__PURE__ */ jsx(ModalContent, { className: contentClassName, zIndex: contentZ, children })
3534
+ /* @__PURE__ */ jsx(
3535
+ ModalContent,
3536
+ {
3537
+ className: cn(
3538
+ contentClassName,
3539
+ depth > 1 && "shadow-[0_0_0_1px_rgba(255,255,255,0.12),0_20px_50px_-5px_rgba(0,0,0,0.4)]"
3540
+ ),
3541
+ zIndex: contentZ,
3542
+ children
3543
+ }
3544
+ )
3534
3545
  ] });
3535
3546
  }
3536
3547
  function ConfirmModal(props) {
@@ -4031,7 +4042,7 @@ function TableHeader(props) {
4031
4042
  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" : "";
4032
4043
  if (column.align === "left") {
4033
4044
  return /* @__PURE__ */ jsxs("div", { className: "flex item-center w-full", children: [
4034
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: `pl-2 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) }),
4045
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: `pl-3 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) }),
4035
4046
  column.sortable && /* @__PURE__ */ jsx(
4036
4047
  "div",
4037
4048
  {
@@ -4062,7 +4073,7 @@ function TableHeader(props) {
4062
4073
  children: renderSortIcon(column.key)
4063
4074
  }
4064
4075
  ),
4065
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: `pr-2 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) })
4076
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: `pr-3 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title }) })
4066
4077
  ] });
4067
4078
  }
4068
4079
  return /* @__PURE__ */ jsx("span", { className: `px-1.5 truncate ${baseClasses} ${isClickableHead} ${subTitleClasses}`, children: column.title });
@@ -4433,7 +4444,7 @@ function SkeletonTd(props) {
4433
4444
  return /* @__PURE__ */ jsx(
4434
4445
  "td",
4435
4446
  {
4436
- 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`,
4447
+ 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`,
4437
4448
  style: {
4438
4449
  width: col.width,
4439
4450
  minWidth: col.minWidth || col.width,
@@ -4505,7 +4516,7 @@ function TableCellContent(props) {
4505
4516
  "div",
4506
4517
  {
4507
4518
  ref: textRef,
4508
- className: "ellipsis-1-line table-item hover:text-main cursor-pointer w-full min-w-0",
4519
+ className: `ellipsis-1-line table-item w-full min-w-0 ${onCellClick ? "hover:text-main cursor-pointer" : "cursor-default"}`,
4509
4520
  style: { textAlign },
4510
4521
  onClick: onCellClick,
4511
4522
  children: shouldShowTooltip ? /* @__PURE__ */ jsx(Tooltip2, { content: tooltipText, position: "bottom", asChild: true, children: /* @__PURE__ */ jsx("span", { children: cellContent }) }) : cellContent
@@ -4974,7 +4985,7 @@ function Table(props) {
4974
4985
  id: `${col.key}-body`,
4975
4986
  "data-row-cell": "true",
4976
4987
  "data-col-key": col.key,
4977
- 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`,
4988
+ 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`,
4978
4989
  style: {
4979
4990
  width,
4980
4991
  minWidth: minWidth || width,
@@ -4991,7 +5002,7 @@ function Table(props) {
4991
5002
  tooltipText: String(record[col.key] ?? ""),
4992
5003
  align: align ?? "",
4993
5004
  tooltipConfig: col.key === "__checkbox__" ? false : tooltipConfig,
4994
- onCellClick: col.key !== "__checkbox__" ? () => onRowClickRef.current?.(record, rowIdx) : void 0
5005
+ onCellClick: col.key !== "__checkbox__" && onRowClickRef.current ? () => onRowClickRef.current?.(record, rowIdx) : void 0
4995
5006
  }
4996
5007
  ) })
4997
5008
  },
@@ -5066,7 +5077,7 @@ function Table(props) {
5066
5077
  const rest = baseRows.filter((row) => !effectiveRowOrder.includes(String(getRowKey(row.original, row.index))));
5067
5078
  return [...ordered, ...rest];
5068
5079
  }, [baseRows, effectiveRowOrder, getRowKey]);
5069
- return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded table-shadow", children: [
5080
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded shadow-panel", children: [
5070
5081
  /* @__PURE__ */ jsx(
5071
5082
  "div",
5072
5083
  {
@@ -5090,7 +5101,7 @@ function Table(props) {
5090
5101
  isColumnDraggable
5091
5102
  }
5092
5103
  ),
5093
- /* @__PURE__ */ jsx("tbody", { className: "w-full h-full", children: showSkeleton ? Array.from({ length: 15 }).map((_, rowIdx) => /* @__PURE__ */ jsxs("tr", { className: "hover:bg-gray-50", children: [
5104
+ /* @__PURE__ */ jsx("tbody", { className: "w-full h-full", children: showSkeleton ? Array.from({ length: 3 }).map((_, rowIdx) => /* @__PURE__ */ jsxs("tr", { className: "hover:bg-gray-50", children: [
5094
5105
  leadingPinnedCols.map((col, idx) => /* @__PURE__ */ jsx(SkeletonTd, { col, showSquare: idx === 0 && !!checkboxInfo }, `leading-${idx}`)),
5095
5106
  leftColspan > 0 && /* @__PURE__ */ jsx("td", { colSpan: leftColspan, style: { padding: 0, border: "none" } }),
5096
5107
  virtualItems.map((vc) => /* @__PURE__ */ jsx(SkeletonTd, { col: groupCols[vc.index] }, `group-${vc.index}`)),
@@ -6804,7 +6815,8 @@ function InputField(props) {
6804
6815
  maxLength,
6805
6816
  className = "",
6806
6817
  type = "input",
6807
- numbersOnly = false
6818
+ numbersOnly = false,
6819
+ autoComplete
6808
6820
  } = config;
6809
6821
  const inputType = type === "email" ? "email" : type === "password" ? "password" : "text";
6810
6822
  if (readOnly) {
@@ -6829,6 +6841,7 @@ function InputField(props) {
6829
6841
  maxLength,
6830
6842
  status: "default",
6831
6843
  className: formControlClass(hasError),
6844
+ autoComplete,
6832
6845
  bare: true,
6833
6846
  onChange: handleChange
6834
6847
  }
@@ -7534,7 +7547,8 @@ function SubmitFormRoot(props) {
7534
7547
  className = "",
7535
7548
  formClassName,
7536
7549
  gridClassName = "grid-cols-12",
7537
- mode = "onSubmit"
7550
+ mode = "onSubmit",
7551
+ autoComplete
7538
7552
  } = props;
7539
7553
  const methods = useForm({
7540
7554
  resolver: zodResolver(schema),
@@ -7557,6 +7571,7 @@ function SubmitFormRoot(props) {
7557
7571
  id: formId,
7558
7572
  onSubmit: handleSubmit,
7559
7573
  className: cn2(SUBMIT_FORM_CLASS, formClassName, className),
7574
+ autoComplete,
7560
7575
  noValidate: true,
7561
7576
  children: /* @__PURE__ */ jsx("div", { className: `grid ${gridClassName} items-stretch gap-0`, children })
7562
7577
  }
@@ -7584,7 +7599,8 @@ function PageFilter(props) {
7584
7599
  colGap = 0,
7585
7600
  submitButtonText = "\uAC80\uC0C9",
7586
7601
  resetButtonText = "\uCD08\uAE30\uD654",
7587
- values
7602
+ values,
7603
+ primaryColor
7588
7604
  } = props;
7589
7605
  const [localValues, setLocalValues] = useState(values);
7590
7606
  const initialValuesRef = useRef(values);
@@ -7642,6 +7658,7 @@ function PageFilter(props) {
7642
7658
  onChange: handleSelectChange(optionKey),
7643
7659
  options: option.options,
7644
7660
  placeholder: "\uC120\uD0DD",
7661
+ canReset: true,
7645
7662
  containerClassName: option.containerClassName ?? "w-30"
7646
7663
  }
7647
7664
  ) }, String(optionKey));
@@ -7694,16 +7711,20 @@ function PageFilter(props) {
7694
7711
  "div",
7695
7712
  {
7696
7713
  className: cn(
7697
- "flex flex-col gap-3 bg-white py-3 px-5 border-t-main border-t-1 shadow-page-filter",
7714
+ "flex flex-col gap-3 bg-white py-3 px-5 border-t-main border-t-1 shadow-panel",
7698
7715
  containerClassName
7699
7716
  ),
7700
- children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: [
7701
- rows.map((row) => /* @__PURE__ */ 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("_"))),
7702
- /* @__PURE__ */ jsxs("div", { className: "absolute right-2 bottom-2 flex justify-end gap-2 pt-2", children: [
7703
- /* @__PURE__ */ jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7704
- onReset && /* @__PURE__ */ jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7705
- ] })
7706
- ] })
7717
+ style: primaryColor ? { borderTopColor: primaryColor } : void 0,
7718
+ children: /* @__PURE__ */ jsx("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: rows.map((row, ix) => {
7719
+ const isLastRow = rows.length - 1 === ix;
7720
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-row min-h-12", children: [
7721
+ row.options.map((option, index) => renderFilterOption(option, rowGap, index)),
7722
+ isLastRow && /* @__PURE__ */ jsxs("div", { className: "ml-4 flex flex-row items-center gap-2", children: [
7723
+ /* @__PURE__ */ jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7724
+ onReset && /* @__PURE__ */ jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7725
+ ] })
7726
+ ] }, row.options.map((opt) => String(opt.key)).join("_"));
7727
+ }) })
7707
7728
  }
7708
7729
  );
7709
7730
  }
@@ -7715,7 +7736,9 @@ var VARIANT_STYLES = {
7715
7736
  activeText: "font-semibold text-gray-800",
7716
7737
  inactiveText: "font-normal",
7717
7738
  indicator: "bg-blue-500",
7718
- closeBtn: "hover:bg-gray-300/60",
7739
+ closeBtn: "rounded hover:bg-gray-300/60",
7740
+ closeBtnWH: "w-3.5 h-3.5",
7741
+ closeBtnSize: 10,
7719
7742
  plusBtnArea: "border-l border-gray-100 bg-white",
7720
7743
  plusBtn: "text-gray-400 hover:text-gray-600 hover:bg-gray-100",
7721
7744
  fadeOpacity: 0.12,
@@ -7732,7 +7755,9 @@ var VARIANT_STYLES = {
7732
7755
  activeText: "font-semibold text-white",
7733
7756
  inactiveText: "font-normal",
7734
7757
  indicator: "bg-indigo-400",
7735
- closeBtn: "hover:bg-gray-600/60",
7758
+ closeBtn: "rounded hover:bg-gray-600/60",
7759
+ closeBtnWH: "w-3.5 h-3.5",
7760
+ closeBtnSize: 10,
7736
7761
  plusBtnArea: "border-l border-gray-700 bg-gray-900",
7737
7762
  plusBtn: "text-gray-500 hover:text-gray-300 hover:bg-gray-700",
7738
7763
  fadeOpacity: 0.4,
@@ -7745,11 +7770,13 @@ var VARIANT_STYLES = {
7745
7770
  "system-light": {
7746
7771
  container: "bg-gray-200 border-b border-gray-300",
7747
7772
  activeTab: "bg-white border-gray-300 text-slate-800 shadow-sm",
7748
- inactiveTab: "bg-transparent border-gray-300/80 text-slate-500 hover:text-slate-700 hover:bg-gray-200 hover:border-gray-300",
7773
+ inactiveTab: "bg-transparent border-gray-300/80 text-slate-500 hover:text-slate-700 hover:bg-[#efefef] hover:border-gray-300",
7749
7774
  activeText: "font-semibold text-slate-800",
7750
7775
  inactiveText: "font-medium",
7751
7776
  indicator: "bg-[#2b2b2b]",
7752
- closeBtn: "hover:bg-gray-300",
7777
+ closeBtn: "ml-auto text-slate-400 hover:text-slate-700",
7778
+ closeBtnWH: "w-4 h-4",
7779
+ closeBtnSize: 13,
7753
7780
  plusBtnArea: "border-l border-gray-300 bg-gray-200",
7754
7781
  plusBtn: "text-slate-400 hover:text-slate-600 hover:bg-gray-300",
7755
7782
  fadeOpacity: 0.15,
@@ -7766,7 +7793,9 @@ var VARIANT_STYLES = {
7766
7793
  activeText: "font-semibold text-slate-100",
7767
7794
  inactiveText: "font-medium",
7768
7795
  indicator: "bg-indigo-400",
7769
- closeBtn: "hover:bg-slate-600/60",
7796
+ closeBtn: "ml-auto text-slate-500 hover:text-slate-200",
7797
+ closeBtnWH: "w-4 h-4",
7798
+ closeBtnSize: 13,
7770
7799
  plusBtnArea: "border-l border-slate-700 bg-slate-900",
7771
7800
  plusBtn: "text-slate-400 hover:text-slate-200 hover:bg-slate-700",
7772
7801
  fadeOpacity: 0.45,
@@ -7919,12 +7948,12 @@ function MultiTabBar(props) {
7919
7948
  onTabClose(tab.id);
7920
7949
  },
7921
7950
  className: `
7922
- flex-shrink-0 w-3.5 h-3.5 flex items-center justify-center
7923
- rounded transition-all duration-100 cursor-pointer
7951
+ flex-shrink-0 ${s.closeBtnWH} flex items-center justify-center
7952
+ transition-all duration-100 cursor-pointer
7924
7953
  ${s.closeBtn}
7925
7954
  ${isActive ? "opacity-100" : "opacity-40 group-hover:opacity-60"}
7926
7955
  `,
7927
- children: /* @__PURE__ */ jsx(X, { size: 10, strokeWidth: 2.5 })
7956
+ children: /* @__PURE__ */ jsx(X, { size: s.closeBtnSize, strokeWidth: 2.5 })
7928
7957
  }
7929
7958
  )
7930
7959
  ]
@@ -8754,7 +8783,8 @@ var VARIANT_STYLES2 = {
8754
8783
  iconClass: "w-4 h-4 flex-shrink-0",
8755
8784
  activeItemStyle: {},
8756
8785
  activeChildStyle: {},
8757
- activeGrandchildStyle: {}
8786
+ activeGrandchildStyle: {},
8787
+ footerBorder: "border-t border-gray-200"
8758
8788
  },
8759
8789
  dark: {
8760
8790
  aside: "bg-gray-900 border-r border-gray-700",
@@ -8780,7 +8810,8 @@ var VARIANT_STYLES2 = {
8780
8810
  iconClass: "w-4 h-4 flex-shrink-0",
8781
8811
  activeItemStyle: {},
8782
8812
  activeChildStyle: {},
8783
- activeGrandchildStyle: {}
8813
+ activeGrandchildStyle: {},
8814
+ footerBorder: "border-t border-gray-700"
8784
8815
  },
8785
8816
  "system-dark": {
8786
8817
  aside: "bg-slate-900 border-r border-slate-700",
@@ -8806,7 +8837,8 @@ var VARIANT_STYLES2 = {
8806
8837
  iconClass: "w-4.5 h-4.5 flex-shrink-0",
8807
8838
  activeItemStyle: { borderLeft: "3px solid #818cf8", paddingLeft: "9px" },
8808
8839
  activeChildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "14px" },
8809
- activeGrandchildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "10px" }
8840
+ activeGrandchildStyle: { borderLeft: "2px solid #818cf8", paddingLeft: "10px" },
8841
+ footerBorder: "border-t border-slate-700"
8810
8842
  },
8811
8843
  "system-light": {
8812
8844
  aside: "bg-gray-50 border-r border-gray-200",
@@ -8847,7 +8879,8 @@ var VARIANT_STYLES2 = {
8847
8879
  backgroundColor: "color-mix(in srgb, #2b2b2b 10%, transparent)",
8848
8880
  borderLeft: "2px solid #2b2b2b",
8849
8881
  paddingLeft: "10px"
8850
- }
8882
+ },
8883
+ footerBorder: "border-t border-gray-200"
8851
8884
  }
8852
8885
  };
8853
8886
  function tintedStyle(color) {
@@ -8924,6 +8957,7 @@ function Sidebar(props) {
8924
8957
  onClose,
8925
8958
  menuSections,
8926
8959
  header,
8960
+ footer,
8927
8961
  className,
8928
8962
  showCollapseButton = false,
8929
8963
  variant = "light",
@@ -8931,8 +8965,17 @@ function Sidebar(props) {
8931
8965
  } = props;
8932
8966
  const { pathname } = useLocation();
8933
8967
  const [isCollapsed, setIsCollapsed] = useState(false);
8968
+ const [overflowVisible, setOverflowVisible] = useState(true);
8934
8969
  const [expandedItems, setExpandedItems] = useState(/* @__PURE__ */ new Set());
8935
8970
  const [expandedSubItems, setExpandedSubItems] = useState(/* @__PURE__ */ new Set());
8971
+ useEffect(() => {
8972
+ if (isCollapsed) {
8973
+ setOverflowVisible(false);
8974
+ return;
8975
+ }
8976
+ const timer = setTimeout(() => setOverflowVisible(true), 300);
8977
+ return () => clearTimeout(timer);
8978
+ }, [isCollapsed]);
8936
8979
  const s = VARIANT_STYLES2[variant];
8937
8980
  const applier = ACCENT_APPLIERS[variant];
8938
8981
  useEffect(() => {
@@ -8994,7 +9037,7 @@ function Sidebar(props) {
8994
9037
  className: `
8995
9038
  ${isCollapsed ? "w-11 min-w-11" : "min-w-60 w-62"}
8996
9039
  transition-[width,min-width] duration-300 ease-in-out
8997
- hide-scrollbar relative h-screen shrink-0 overflow-y-auto overflow-x-hidden
9040
+ relative h-screen shrink-0 overflow-x-hidden flex flex-col
8998
9041
  ${s.aside}
8999
9042
  ${className ?? ""}
9000
9043
  `,
@@ -9007,14 +9050,14 @@ function Sidebar(props) {
9007
9050
  children: isCollapsed ? /* @__PURE__ */ jsx(PanelRightClose, { size: 18, color: primaryColor ?? s.collapseIcon }) : /* @__PURE__ */ jsx(PanelLeftClose, { size: 18, color: primaryColor ?? s.collapseIcon })
9008
9051
  }
9009
9052
  ),
9010
- /* @__PURE__ */ jsxs(
9053
+ /* @__PURE__ */ jsx("div", { className: `flex-1 min-h-0 hide-scrollbar ${overflowVisible ? "overflow-y-auto" : "overflow-hidden"}`, children: /* @__PURE__ */ jsxs(
9011
9054
  "div",
9012
9055
  {
9013
- className: `transition-opacity duration-200 ease-in-out ${isCollapsed ? "opacity-0 pointer-events-none select-none" : "opacity-100"} ${variant === "system-dark" || variant === "system-light" ? "px-1 py-6" : "px-4 py-6"}`,
9056
+ 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"}`,
9014
9057
  style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9015
9058
  children: [
9016
- header && /* @__PURE__ */ jsx("div", { className: "mb-6 mt-2", children: header }),
9017
- /* @__PURE__ */ jsx("nav", { className: "space-y-6", children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
9059
+ header && header,
9060
+ /* @__PURE__ */ jsx("nav", { className: `space-y-6 ${variant === "system-dark" || variant === "system-light" ? "px-1" : ""}`, children: menuSections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
9018
9061
  section.title && /* @__PURE__ */ jsx("div", { className: s.sectionTitle, children: section.title }),
9019
9062
  /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => {
9020
9063
  const isActive = !item.children && pathname === item.path;
@@ -9153,6 +9196,14 @@ function Sidebar(props) {
9153
9196
  ] }, section.title ?? sectionIndex)) })
9154
9197
  ]
9155
9198
  }
9199
+ ) }),
9200
+ footer && /* @__PURE__ */ jsx(
9201
+ "div",
9202
+ {
9203
+ className: `flex-shrink-0 transition-opacity duration-200 ease-in-out ${isCollapsed ? "opacity-0 pointer-events-none select-none" : "opacity-100"} ${s.footerBorder}`,
9204
+ style: { transitionDelay: isCollapsed ? "0ms" : "150ms" },
9205
+ children: footer
9206
+ }
9156
9207
  )
9157
9208
  ]
9158
9209
  }
@@ -9471,7 +9522,7 @@ function DetailModalFrame(props) {
9471
9522
  ) }),
9472
9523
  renderExtraContent?.({ isEditMode })
9473
9524
  ] }),
9474
- /* @__PURE__ */ jsx(ModalFooter, { className: "flex justify-end gap-2", children: isEditMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
9525
+ /* @__PURE__ */ jsx(ModalFooter, { className: "flex justify-end", children: isEditMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
9475
9526
  /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleCancelEdit, disabled: controller.isSaving, children: "\uCDE8\uC18C" }),
9476
9527
  /* @__PURE__ */ jsx(Button, { type: "submit", form: controller.formId, variant: "save", disabled: controller.isSaving, children: "\uC800\uC7A5" })
9477
9528
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [