@farmzone/fz-react-ui 1.0.6 → 1.0.8

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
@@ -650,6 +650,8 @@ interface CheckboxInfo {
650
650
  selectedKeys: Array<string | number>;
651
651
  onSelectionChange: (keys: Array<string | number>) => void;
652
652
  fixed?: boolean;
653
+ disabledKeys?: Array<string | number>;
654
+ disabledTooltip?: React.ReactNode | ((key: string | number) => React.ReactNode);
653
655
  }
654
656
  type DragEndResult = {
655
657
  type: "row" | "column";
@@ -674,6 +676,8 @@ interface TableProps<T> {
674
676
  onColumnDragEnd?: (result: DragEndResult) => void;
675
677
  tooltipConfig?: "always" | "overflow" | false;
676
678
  isDynamicHeight?: boolean;
679
+ showHorizontalDivider?: boolean;
680
+ showVerticalDivider?: boolean;
677
681
  }
678
682
  declare function Table<T>(props: TableProps<T>): react.JSX.Element;
679
683
 
@@ -1239,6 +1243,8 @@ interface DetailModalFrameProps<T, S extends z.ZodTypeAny = z.ZodTypeAny> {
1239
1243
  renderFooterExtra?: ReactNode;
1240
1244
  /** isDirty 상태 외부 노출 — 라우터 blocker 등에서 활용 */
1241
1245
  onDirtyChange?: (isDirty: boolean) => void;
1246
+ /** 제공 시 ModalIconHeader로 렌더링 (read 모드: 이 type, edit 모드: "edit" 자동 적용) */
1247
+ headerType?: ModalType;
1242
1248
  }
1243
1249
  declare function DetailModalFrame<T, S extends z.ZodTypeAny = z.ZodTypeAny>(props: DetailModalFrameProps<T, S>): react.JSX.Element;
1244
1250
 
@@ -1371,7 +1377,7 @@ declare const textVariants: (props?: ({
1371
1377
  declare const Z_INDEX: {
1372
1378
  readonly TABLE_COL_STICKY: 1;
1373
1379
  readonly TABLE_FIXED_CELL: 5;
1374
- readonly TABLE_FIXED_HEADER_CELL: 10;
1380
+ readonly TABLE_FIXED_HEADER_CELL: 15;
1375
1381
  readonly LOCAL_OVERLAY: 10;
1376
1382
  readonly LAYOUT_HEADER: 20;
1377
1383
  readonly DROPDOWN_LOCAL: 20;
package/dist/index.d.ts CHANGED
@@ -650,6 +650,8 @@ interface CheckboxInfo {
650
650
  selectedKeys: Array<string | number>;
651
651
  onSelectionChange: (keys: Array<string | number>) => void;
652
652
  fixed?: boolean;
653
+ disabledKeys?: Array<string | number>;
654
+ disabledTooltip?: React.ReactNode | ((key: string | number) => React.ReactNode);
653
655
  }
654
656
  type DragEndResult = {
655
657
  type: "row" | "column";
@@ -674,6 +676,8 @@ interface TableProps<T> {
674
676
  onColumnDragEnd?: (result: DragEndResult) => void;
675
677
  tooltipConfig?: "always" | "overflow" | false;
676
678
  isDynamicHeight?: boolean;
679
+ showHorizontalDivider?: boolean;
680
+ showVerticalDivider?: boolean;
677
681
  }
678
682
  declare function Table<T>(props: TableProps<T>): react.JSX.Element;
679
683
 
@@ -1239,6 +1243,8 @@ interface DetailModalFrameProps<T, S extends z.ZodTypeAny = z.ZodTypeAny> {
1239
1243
  renderFooterExtra?: ReactNode;
1240
1244
  /** isDirty 상태 외부 노출 — 라우터 blocker 등에서 활용 */
1241
1245
  onDirtyChange?: (isDirty: boolean) => void;
1246
+ /** 제공 시 ModalIconHeader로 렌더링 (read 모드: 이 type, edit 모드: "edit" 자동 적용) */
1247
+ headerType?: ModalType;
1242
1248
  }
1243
1249
  declare function DetailModalFrame<T, S extends z.ZodTypeAny = z.ZodTypeAny>(props: DetailModalFrameProps<T, S>): react.JSX.Element;
1244
1250
 
@@ -1371,7 +1377,7 @@ declare const textVariants: (props?: ({
1371
1377
  declare const Z_INDEX: {
1372
1378
  readonly TABLE_COL_STICKY: 1;
1373
1379
  readonly TABLE_FIXED_CELL: 5;
1374
- readonly TABLE_FIXED_HEADER_CELL: 10;
1380
+ readonly TABLE_FIXED_HEADER_CELL: 15;
1375
1381
  readonly LOCAL_OVERLAY: 10;
1376
1382
  readonly LAYOUT_HEADER: 20;
1377
1383
  readonly DROPDOWN_LOCAL: 20;
package/dist/index.js CHANGED
@@ -214,7 +214,7 @@ function TooltipContent({
214
214
  var Z_INDEX = {
215
215
  TABLE_COL_STICKY: 1,
216
216
  TABLE_FIXED_CELL: 5,
217
- TABLE_FIXED_HEADER_CELL: 10,
217
+ TABLE_FIXED_HEADER_CELL: 15,
218
218
  LOCAL_OVERLAY: 10,
219
219
  LAYOUT_HEADER: 20,
220
220
  DROPDOWN_LOCAL: 20,
@@ -465,12 +465,10 @@ function Input2(props) {
465
465
  const actualType = type === "password" && showPassword ? "text" : type;
466
466
  const handlePasswordToggle = () => setShowPassword((prev) => !prev);
467
467
  const finalRightIcon = rightIcon || (shouldShowPasswordToggle ? /* @__PURE__ */ jsx(
468
- "button",
468
+ "div",
469
469
  {
470
- type: "button",
471
470
  onClick: handlePasswordToggle,
472
471
  className: "text-muted-foreground hover:text-foreground cursor-pointer transition-colors",
473
- disabled,
474
472
  children: showPassword ? /* @__PURE__ */ jsx(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Eye, { className: "h-4 w-4" })
475
473
  }
476
474
  ) : null);
@@ -3719,7 +3717,7 @@ function confirmModal(options) {
3719
3717
  }
3720
3718
  function TableFooter(props) {
3721
3719
  const { paginationInfo, renderLeft, renderRight } = props;
3722
- return /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-4 min-h-16", children: [
3720
+ return /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-4 min-h-16 border-t-1 border-gray-100", children: [
3723
3721
  /* @__PURE__ */ jsx("div", { className: "flex justify-start flex-1 min-w-0", children: renderLeft }),
3724
3722
  paginationInfo && /* @__PURE__ */ jsx("div", { className: "px-5", children: /* @__PURE__ */ jsx(Pagination, { ...paginationInfo }) }),
3725
3723
  /* @__PURE__ */ jsx("div", { className: "flex justify-end flex-1 min-w-0", children: renderRight })
@@ -3929,8 +3927,6 @@ function ArrowIcon(props) {
3929
3927
  }
3930
3928
  );
3931
3929
  }
3932
- var DEFAULT_SORT_KEY = "";
3933
- var DEFAULT_SORT_ORDER = "asc";
3934
3930
  var DEFAULT_SORT_OPTIONS = {
3935
3931
  visibleType: "always",
3936
3932
  sortKey: "",
@@ -3979,27 +3975,18 @@ function TableHeader(props) {
3979
3975
  if (onSortChange) {
3980
3976
  const isActive = sortOption?.sortKey === columnKey;
3981
3977
  const currentOrder = sortOption?.sortOrder;
3982
- if (isActive) {
3983
- if (currentOrder === "desc") {
3984
- onSortChange(columnKey, "asc");
3985
- } else if (currentOrder === "asc") {
3986
- onSortChange(DEFAULT_SORT_KEY, DEFAULT_SORT_ORDER);
3987
- } else {
3988
- onSortChange(columnKey, "desc");
3989
- }
3978
+ if (isActive && currentOrder === "desc") {
3979
+ onSortChange(columnKey, "asc");
3990
3980
  } else {
3991
3981
  onSortChange(columnKey, "desc");
3992
3982
  }
3993
3983
  return;
3994
3984
  }
3995
3985
  setInternalSortState((prev) => {
3996
- if (prev.columnKey !== columnKey) {
3997
- return { columnKey, order: "desc" };
3998
- }
3999
- if (prev.order === "desc") {
3986
+ if (prev.columnKey === columnKey && prev.order === "desc") {
4000
3987
  return { columnKey, order: "asc" };
4001
3988
  }
4002
- return { columnKey: null, order: null };
3989
+ return { columnKey, order: "desc" };
4003
3990
  });
4004
3991
  };
4005
3992
  const renderSortIcon = (columnKey) => {
@@ -4635,9 +4622,11 @@ function Table(props) {
4635
4622
  paginationInfo,
4636
4623
  renderFooter,
4637
4624
  tooltipConfig = "overflow",
4638
- isDynamicHeight = true
4625
+ isDynamicHeight = true,
4626
+ showHorizontalDivider = true,
4627
+ showVerticalDivider = true
4639
4628
  } = props;
4640
- const { fixed = false, onSelectionChange, selectedKeys = [] } = checkboxInfo ?? {};
4629
+ const { fixed = false, onSelectionChange, selectedKeys = [], disabledKeys = [], disabledTooltip } = checkboxInfo ?? {};
4641
4630
  const scrollRef = useRef(null);
4642
4631
  const footerRef = useRef(null);
4643
4632
  const [tableHeight, setTableHeight] = useState(500);
@@ -4679,11 +4668,14 @@ function Table(props) {
4679
4668
  const footerH = footerRef.current?.getBoundingClientRect().height ?? 0;
4680
4669
  setTableHeight(window.innerHeight - top - footerH - 24);
4681
4670
  }, [showSkeleton, showEmpty]);
4682
- const isAllSelected = data.length > 0 && selectedKeys.length === data.length;
4683
4671
  const selectedKeysRef = useRef(selectedKeys);
4684
4672
  selectedKeysRef.current = selectedKeys;
4685
4673
  const onSelectionChangeRef = useRef(onSelectionChange);
4686
4674
  onSelectionChangeRef.current = onSelectionChange;
4675
+ const disabledKeysRef = useRef(disabledKeys);
4676
+ disabledKeysRef.current = disabledKeys;
4677
+ const disabledTooltipRef = useRef(disabledTooltip);
4678
+ disabledTooltipRef.current = disabledTooltip;
4687
4679
  const dataRef = useRef(data);
4688
4680
  dataRef.current = data;
4689
4681
  const onRowClickRef = useRef(onRowClick);
@@ -4698,6 +4690,8 @@ function Table(props) {
4698
4690
  },
4699
4691
  [rowKey]
4700
4692
  );
4693
+ const selectableKeys = data.map((record, index) => getRowKey(record, index)).filter((key) => !disabledKeys.includes(key));
4694
+ const isAllSelected = selectableKeys.length > 0 && selectableKeys.every((key) => selectedKeys.includes(key));
4701
4695
  const allColumns = useMemo(() => {
4702
4696
  const checkboxCol = {
4703
4697
  key: "__checkbox__",
@@ -4712,19 +4706,24 @@ function Table(props) {
4712
4706
  checked: isAllSelected,
4713
4707
  onChange: () => {
4714
4708
  if (!onSelectionChangeRef.current) return;
4715
- const allKeys = dataRef.current.map((record, index) => getRowKey(record, index));
4709
+ const allKeys = dataRef.current.map((record, index) => getRowKey(record, index)).filter((key) => !disabledKeysRef.current.includes(key));
4716
4710
  onSelectionChangeRef.current(isAllSelected ? [] : allKeys);
4717
4711
  }
4718
4712
  }
4719
4713
  ),
4720
4714
  render: (_value, record, rowIdx) => {
4721
4715
  const key = getRowKey(record, rowIdx);
4716
+ const isDisabled = disabledKeysRef.current.includes(key);
4717
+ const tooltip = disabledTooltipRef.current;
4718
+ const tooltipContent = isDisabled && tooltip ? typeof tooltip === "function" ? tooltip(key) : tooltip : void 0;
4722
4719
  return /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx(
4723
4720
  Checkbox,
4724
4721
  {
4725
4722
  checked: selectedKeysRef.current.includes(key),
4723
+ disabled: isDisabled,
4724
+ tooltipConfig: tooltipContent ? { content: tooltipContent, position: "bottom" } : void 0,
4726
4725
  onChange: () => {
4727
- if (!onSelectionChangeRef.current) return;
4726
+ if (!onSelectionChangeRef.current || isDisabled) return;
4728
4727
  const cur = selectedKeysRef.current;
4729
4728
  const next = cur.includes(key) ? cur.filter((k) => k !== key) : [...cur, key];
4730
4729
  onSelectionChangeRef.current(next);
@@ -4985,7 +4984,7 @@ function Table(props) {
4985
4984
  id: `${col.key}-body`,
4986
4985
  "data-row-cell": "true",
4987
4986
  "data-col-key": col.key,
4988
- 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`,
4987
+ className: `${isCheckbox ? "p-0" : "p-3"} whitespace-nowrap text-sm text-gray-900 border-gray-300/70 last:border-r-0 bg-inherit group-hover:bg-gray-100 transition-all ${showVerticalDivider ? "border-r" : ""} ${showHorizontalDivider ? "border-b" : ""}`,
4989
4988
  style: {
4990
4989
  width,
4991
4990
  minWidth: minWidth || width,
@@ -5077,7 +5076,7 @@ function Table(props) {
5077
5076
  const rest = baseRows.filter((row) => !effectiveRowOrder.includes(String(getRowKey(row.original, row.index))));
5078
5077
  return [...ordered, ...rest];
5079
5078
  }, [baseRows, effectiveRowOrder, getRowKey]);
5080
- return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded shadow-panel", children: [
5079
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded shadow-table border border-gray-200 overflow-hidden", children: [
5081
5080
  /* @__PURE__ */ jsx(
5082
5081
  "div",
5083
5082
  {
@@ -5085,7 +5084,7 @@ function Table(props) {
5085
5084
  ref: scrollRef,
5086
5085
  className: "relative w-full overflow-y-auto overflow-x-auto custom-view-scrollbar bg-white",
5087
5086
  style: { height: `${tableHeight}px` },
5088
- children: /* @__PURE__ */ jsxs("table", { className: "w-full table-fixed", children: [
5087
+ children: /* @__PURE__ */ jsxs("table", { className: "w-full table-fixed border-spacing-0", children: [
5089
5088
  /* @__PURE__ */ jsx(
5090
5089
  TableHeader,
5091
5090
  {
@@ -7624,7 +7623,7 @@ var SubmitForm = Object.assign(SubmitFormRoot, {
7624
7623
  });
7625
7624
  function LabeledFilterOption(props) {
7626
7625
  const { label, children, gap } = props;
7627
- return /* @__PURE__ */ jsxs("div", { style: { marginLeft: gap }, className: "flex flex-row items-center gap-5", children: [
7626
+ return /* @__PURE__ */ jsxs("div", { style: { marginLeft: gap }, className: "flex flex-row items-center gap-4", children: [
7628
7627
  label && /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-gray-60 shrink-0", children: label }),
7629
7628
  children
7630
7629
  ] });
@@ -7636,7 +7635,7 @@ function PageFilter(props) {
7636
7635
  onSubmit,
7637
7636
  onReset,
7638
7637
  containerClassName,
7639
- rowGap = 32,
7638
+ rowGap = 28,
7640
7639
  colGap = 0,
7641
7640
  submitButtonText = "\uAC80\uC0C9",
7642
7641
  resetButtonText = "\uCD08\uAE30\uD654",
@@ -7750,9 +7749,9 @@ function PageFilter(props) {
7750
7749
  style: primaryColor ? { borderTopColor: primaryColor } : void 0,
7751
7750
  children: /* @__PURE__ */ jsx("div", { className: "relative flex flex-col", style: { gap: `${colGap}px` }, children: rows.map((row, ix) => {
7752
7751
  const isLastRow = rows.length - 1 === ix;
7753
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-row min-h-12", children: [
7752
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-row min-h-11", children: [
7754
7753
  row.options.map((option, index) => renderFilterOption(option, rowGap, index)),
7755
- isLastRow && /* @__PURE__ */ jsxs("div", { className: "ml-4 flex flex-row items-center gap-2", children: [
7754
+ isLastRow && /* @__PURE__ */ jsxs("div", { className: "ml-2 flex flex-row items-center gap-2", children: [
7756
7755
  /* @__PURE__ */ jsx(Button, { variant: "search", onClick: handleSubmit, children: submitButtonText }),
7757
7756
  onReset && /* @__PURE__ */ jsx(Button, { variant: "reset", onClick: handleReset, children: resetButtonText })
7758
7757
  ] })
@@ -9498,7 +9497,8 @@ function DetailModalFrame(props) {
9498
9497
  contentClassName,
9499
9498
  renderExtraContent,
9500
9499
  renderFooterExtra,
9501
- onDirtyChange
9500
+ onDirtyChange,
9501
+ headerType
9502
9502
  } = props;
9503
9503
  const controller = useDetailController({ mode, onModeChange });
9504
9504
  useEffect(() => {
@@ -9537,7 +9537,14 @@ function DetailModalFrame(props) {
9537
9537
  const isEditMode = controller.mode === "edit";
9538
9538
  const canEdit = Boolean(editSchema && (editFields || renderEditBody));
9539
9539
  return /* @__PURE__ */ jsxs(Modal, { isOpen: open, onClose: handleClose, contentClassName: cn("max-w-2xl", contentClassName), children: [
9540
- /* @__PURE__ */ jsx(ModalHeader, { className: "flex flex-row items-center justify-between", children: /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900", children: title }) }),
9540
+ headerType ? /* @__PURE__ */ jsx(
9541
+ ModalIconHeader,
9542
+ {
9543
+ type: isEditMode ? "edit" : headerType,
9544
+ title,
9545
+ onClose: handleClose
9546
+ }
9547
+ ) : /* @__PURE__ */ jsx(ModalHeader, { className: "flex flex-row items-center justify-between", children: /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900", children: title }) }),
9541
9548
  /* @__PURE__ */ jsxs(ModalBody, { className: "flex-1 min-h-0 overflow-hidden p-0 flex flex-col", children: [
9542
9549
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsx(
9543
9550
  DetailContent,