@farmzone/fz-react-ui 1.1.4 → 1.1.6

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
@@ -91,6 +91,8 @@ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
91
91
  leftIcon?: ReactNode;
92
92
  rightIcon?: ReactNode;
93
93
  showPasswordToggle?: boolean;
94
+ clearable?: boolean;
95
+ onClear?: () => void;
94
96
  }
95
97
  declare function Input(props: InputProps): react.JSX.Element;
96
98
 
@@ -194,6 +196,9 @@ interface SelectOptionType {
194
196
  label: string | ReactNode;
195
197
  value: string;
196
198
  disabled?: boolean;
199
+ icon?: ReactNode;
200
+ avatarUrl?: string;
201
+ avatarAlt?: string;
197
202
  }
198
203
 
199
204
  interface SelectProps<T extends SelectOptionType = SelectOptionType> extends Omit<React.ComponentProps<typeof Select$1>, "onValueChange" | "value" | "defaultValue"> {
@@ -966,12 +971,15 @@ type SelectableOption = {
966
971
  interface BaseOption<P> {
967
972
  label?: string;
968
973
  key: keyof P;
974
+ className?: string;
969
975
  }
970
976
  type InputOption<P> = BaseOption<P> & {
971
977
  type: "input";
972
978
  placeholder?: string;
973
979
  /** 입력창 왼쪽에 돋보기 아이콘을 보여줄지 여부. 기본값 true. */
974
980
  leftIcon?: boolean;
981
+ /** 입력값이 있을 때 x(clear) 버튼을 보여줄지 여부. 기본값 true. */
982
+ canReset?: boolean;
975
983
  };
976
984
  type SelectOption<P> = BaseOption<P> & {
977
985
  type: "select";
package/dist/index.d.ts CHANGED
@@ -91,6 +91,8 @@ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
91
91
  leftIcon?: ReactNode;
92
92
  rightIcon?: ReactNode;
93
93
  showPasswordToggle?: boolean;
94
+ clearable?: boolean;
95
+ onClear?: () => void;
94
96
  }
95
97
  declare function Input(props: InputProps): react.JSX.Element;
96
98
 
@@ -194,6 +196,9 @@ interface SelectOptionType {
194
196
  label: string | ReactNode;
195
197
  value: string;
196
198
  disabled?: boolean;
199
+ icon?: ReactNode;
200
+ avatarUrl?: string;
201
+ avatarAlt?: string;
197
202
  }
198
203
 
199
204
  interface SelectProps<T extends SelectOptionType = SelectOptionType> extends Omit<React.ComponentProps<typeof Select$1>, "onValueChange" | "value" | "defaultValue"> {
@@ -966,12 +971,15 @@ type SelectableOption = {
966
971
  interface BaseOption<P> {
967
972
  label?: string;
968
973
  key: keyof P;
974
+ className?: string;
969
975
  }
970
976
  type InputOption<P> = BaseOption<P> & {
971
977
  type: "input";
972
978
  placeholder?: string;
973
979
  /** 입력창 왼쪽에 돋보기 아이콘을 보여줄지 여부. 기본값 true. */
974
980
  leftIcon?: boolean;
981
+ /** 입력값이 있을 때 x(clear) 버튼을 보여줄지 여부. 기본값 true. */
982
+ canReset?: boolean;
975
983
  };
976
984
  type SelectOption<P> = BaseOption<P> & {
977
985
  type: "select";
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import * as React6 from 'react';
6
6
  import React6__default, { forwardRef, useState, useRef, useEffect, useImperativeHandle, useCallback, memo, createContext, useContext, useMemo, useId, useLayoutEffect, useDeferredValue, Fragment as Fragment$1 } from 'react';
7
7
  import { Slot } from '@radix-ui/react-slot';
8
8
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
- import { ChevronLeft, ChevronRight, FileText, ZoomIn, ZoomOut, RotateCcw, RotateCw, Download, X, Heading1, Heading2, Heading3, Heading4, Bold, Italic, Strikethrough, Code, AlignLeft, AlignCenter, AlignRight, List, ListOrdered, Quote, FileCode, Table as Table$1, Plus, Minus, Trash2, EyeOff, Eye, Check, CircleX, ChevronDown, Calendar, CircleIcon, ChevronUp, Search, TriangleAlert, Info, Pencil, BadgePlus, FileSearch2, Upload, FileUp, PanelRightClose, PanelLeftClose, ChevronFirst, ChevronLast } from 'lucide-react';
9
+ import { ChevronLeft, ChevronRight, FileText, ZoomIn, ZoomOut, RotateCcw, RotateCw, Download, X, Heading1, Heading2, Heading3, Heading4, Bold, Italic, Strikethrough, Code, AlignLeft, AlignCenter, AlignRight, List, ListOrdered, Quote, FileCode, Table as Table$1, Plus, Minus, Trash2, CircleX, EyeOff, Eye, Check, ChevronDown, Calendar, CircleIcon, ChevronUp, Search, TriangleAlert, Info, Pencil, BadgePlus, FileSearch2, Upload, FileUp, PanelRightClose, PanelLeftClose, ChevronFirst, ChevronLast } from 'lucide-react';
10
10
  import * as SwitchPrimitive from '@radix-ui/react-switch';
11
11
  import * as RadixSlider from '@radix-ui/react-slider';
12
12
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -445,6 +445,8 @@ function Input2(props) {
445
445
  leftIcon,
446
446
  rightIcon,
447
447
  showPasswordToggle = true,
448
+ clearable = false,
449
+ onClear,
448
450
  onChange,
449
451
  ...rest
450
452
  } = props;
@@ -474,7 +476,16 @@ function Input2(props) {
474
476
  const shouldShowPasswordToggle = type === "password" && showPasswordToggle;
475
477
  const actualType = type === "password" && showPassword ? "text" : type;
476
478
  const handlePasswordToggle = () => setShowPassword((prev) => !prev);
477
- const finalRightIcon = rightIcon || (shouldShowPasswordToggle ? /* @__PURE__ */ jsx(
479
+ const handleClear = () => onClear?.();
480
+ const shouldShowClearButton = clearable && !disabled && typeof rest.value === "string" && rest.value.length > 0;
481
+ const finalRightIcon = rightIcon || (shouldShowClearButton ? /* @__PURE__ */ jsx(
482
+ "div",
483
+ {
484
+ onClick: handleClear,
485
+ className: "text-muted-foreground hover:text-foreground cursor-pointer transition-colors",
486
+ children: /* @__PURE__ */ jsx(CircleX, { className: "h-4 w-4" })
487
+ }
488
+ ) : null) || (shouldShowPasswordToggle ? /* @__PURE__ */ jsx(
478
489
  "div",
479
490
  {
480
491
  onClick: handlePasswordToggle,
@@ -940,6 +951,29 @@ function SelectScrollDownButton({
940
951
  }
941
952
  );
942
953
  }
954
+ function SelectOptionVisual(props) {
955
+ const { icon, avatarUrl, avatarAlt, fallbackLabel } = props;
956
+ const [hasAvatarError, setHasAvatarError] = useState(false);
957
+ const handleAvatarError = () => setHasAvatarError(true);
958
+ if (avatarUrl && !hasAvatarError) {
959
+ return /* @__PURE__ */ jsx(
960
+ "img",
961
+ {
962
+ src: avatarUrl,
963
+ alt: avatarAlt ?? "",
964
+ className: "size-5 shrink-0 rounded-full object-cover",
965
+ onError: handleAvatarError
966
+ }
967
+ );
968
+ }
969
+ if (avatarUrl && hasAvatarError) {
970
+ return /* @__PURE__ */ jsx("span", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-gray-200 text-[10px] font-medium text-gray-500", children: fallbackLabel?.charAt(0).toUpperCase() ?? "?" });
971
+ }
972
+ if (icon) {
973
+ return /* @__PURE__ */ jsx("span", { className: "flex size-4 shrink-0 items-center justify-center text-gray-500", children: icon });
974
+ }
975
+ return null;
976
+ }
943
977
 
944
978
  // src/components/Select/config/default.ts
945
979
  var SELECT_BORDER_COLORS = {
@@ -1031,7 +1065,18 @@ function Select2(props) {
1031
1065
  itemClassName,
1032
1066
  option.disabled && cn("opacity-50 cursor-not-allowed text-gray-300 bg-white", disabledItemClassName)
1033
1067
  ),
1034
- children: option.label
1068
+ children: /* @__PURE__ */ jsxs("span", { className: "flex w-full min-w-0 items-center gap-2", children: [
1069
+ /* @__PURE__ */ jsx(
1070
+ SelectOptionVisual,
1071
+ {
1072
+ icon: option.icon,
1073
+ avatarUrl: option.avatarUrl,
1074
+ avatarAlt: option.avatarAlt,
1075
+ fallbackLabel: typeof option.label === "string" ? option.label : void 0
1076
+ }
1077
+ ),
1078
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: option.label })
1079
+ ] })
1035
1080
  },
1036
1081
  String(option.value)
1037
1082
  )) })
@@ -7847,6 +7892,9 @@ function PageFilter(props) {
7847
7892
  const handleInputChange = (key) => (e) => {
7848
7893
  onChange({ [key]: e.target.value });
7849
7894
  };
7895
+ const handleInputClear = (key) => () => {
7896
+ onChange({ [key]: "" });
7897
+ };
7850
7898
  const handleSelectChange = (key, autoSubmit) => (value) => {
7851
7899
  onChange({ [key]: value });
7852
7900
  if (autoSubmit) pendingAutoSubmitRef.current = { key, value };
@@ -7890,7 +7938,10 @@ function PageFilter(props) {
7890
7938
  onKeyDown: (e) => {
7891
7939
  if (e.key === "Enter") handleSubmit();
7892
7940
  },
7893
- leftIcon: option.leftIcon !== false ? /* @__PURE__ */ jsx(Search, { size: 16 }) : void 0
7941
+ leftIcon: option.leftIcon !== false ? /* @__PURE__ */ jsx(Search, { size: 16 }) : void 0,
7942
+ clearable: option.canReset ?? true,
7943
+ onClear: handleInputClear(optionKey),
7944
+ className: option.className
7894
7945
  }
7895
7946
  ) }, String(optionKey));
7896
7947
  case "select":
@@ -7902,7 +7953,8 @@ function PageFilter(props) {
7902
7953
  options: option.options,
7903
7954
  placeholder: option.placeholder || "\uC120\uD0DD",
7904
7955
  canReset: option.canReset ?? true,
7905
- containerClassName: option.containerClassName ?? "w-30"
7956
+ containerClassName: option.containerClassName ?? "w-30",
7957
+ className: option.className
7906
7958
  }
7907
7959
  ) }, String(optionKey));
7908
7960
  case "radio":
@@ -7913,7 +7965,8 @@ function PageFilter(props) {
7913
7965
  value: currentValue,
7914
7966
  onChange: handleRadioChange(optionKey, option.autoSubmit),
7915
7967
  options: option.options,
7916
- direction: "horizontal"
7968
+ direction: "horizontal",
7969
+ containerClassName: option.className
7917
7970
  }
7918
7971
  ) }, String(optionKey));
7919
7972
  case "date":
@@ -7923,7 +7976,8 @@ function PageFilter(props) {
7923
7976
  value: currentValue,
7924
7977
  onChange: handleDateChange(optionKey),
7925
7978
  placeholder: option.placeholder,
7926
- onKeyDownEnter: handleSubmit
7979
+ onKeyDownEnter: handleSubmit,
7980
+ className: option.className
7927
7981
  }
7928
7982
  ) }, String(optionKey));
7929
7983
  case "date-range":
@@ -7933,7 +7987,8 @@ function PageFilter(props) {
7933
7987
  startValue: currentValue,
7934
7988
  endValue: String(values[option.endKey] ?? ""),
7935
7989
  onRangeChange: handleRangeChangeCurried(optionKey, option.endKey),
7936
- onKeyDownEnter: handleSubmit
7990
+ onKeyDownEnter: handleSubmit,
7991
+ className: option.className
7937
7992
  }
7938
7993
  ) }, String(optionKey));
7939
7994
  case "checkbox":
@@ -7944,7 +7999,8 @@ function PageFilter(props) {
7944
7999
  name: String(optionKey),
7945
8000
  value: currentValue,
7946
8001
  label: option.label,
7947
- onChange: handleCheckboxChange(optionKey, option.autoSubmit)
8002
+ onChange: handleCheckboxChange(optionKey, option.autoSubmit),
8003
+ className: option.className
7948
8004
  }
7949
8005
  ) }, String(optionKey));
7950
8006
  default: {