@onesaz/ui 0.3.5 → 0.3.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.ts CHANGED
@@ -679,12 +679,13 @@ interface ComboboxOption {
679
679
  disabled?: boolean;
680
680
  }
681
681
  type ComboboxPrimitiveOption = string;
682
- type ComboboxObjectOption = Record<string, unknown>;
683
- interface ComboboxSingleProps {
684
- options: ComboboxOption[] | ComboboxPrimitiveOption[] | ComboboxObjectOption[];
685
- value?: ComboboxOption | null;
686
- defaultValue?: ComboboxOption | null;
687
- onChange?: (value: ComboboxOption | null) => void;
682
+ type ComboboxObjectOption = object;
683
+ type ComboboxOptionInput = ComboboxPrimitiveOption | ComboboxObjectOption;
684
+ interface ComboboxSingleProps<T extends ComboboxOptionInput = ComboboxOptionInput> {
685
+ options: T[];
686
+ value?: T | null;
687
+ defaultValue?: T | null;
688
+ onChange?: (value: T | null) => void;
688
689
  placeholder?: string;
689
690
  searchPlaceholder?: string;
690
691
  emptyMessage?: string;
@@ -699,11 +700,11 @@ interface ComboboxSingleProps {
699
700
  labelKey?: string;
700
701
  valueKey?: string;
701
702
  }
702
- interface ComboboxMultipleProps {
703
- options: ComboboxOption[] | ComboboxPrimitiveOption[] | ComboboxObjectOption[];
704
- value?: ComboboxOption[];
705
- defaultValue?: ComboboxOption[];
706
- onChange?: (value: ComboboxOption[]) => void;
703
+ interface ComboboxMultipleProps<T extends ComboboxOptionInput = ComboboxOptionInput> {
704
+ options: T[];
705
+ value?: T[];
706
+ defaultValue?: T[];
707
+ onChange?: (value: T[]) => void;
707
708
  placeholder?: string;
708
709
  searchPlaceholder?: string;
709
710
  emptyMessage?: string;
package/dist/index.js CHANGED
@@ -2977,21 +2977,36 @@ var Combobox = React30.forwardRef(
2977
2977
  } = props;
2978
2978
  const labelKey = props.labelKey ?? "label";
2979
2979
  const valueKey = props.valueKey ?? "value";
2980
- const normalizedOptions = React30.useMemo(() => {
2981
- return (options ?? []).map((option) => {
2982
- if (typeof option === "string") {
2983
- return { label: option, value: option };
2984
- }
2980
+ const getOptionLabel = React30.useCallback(
2981
+ (option) => {
2982
+ if (typeof option === "string") return option;
2985
2983
  const record = option;
2986
2984
  const maybeLabel = record[labelKey];
2985
+ return typeof maybeLabel === "string" ? maybeLabel : String(maybeLabel ?? "");
2986
+ },
2987
+ [labelKey]
2988
+ );
2989
+ const getOptionValue = React30.useCallback(
2990
+ (option) => {
2991
+ if (typeof option === "string") return option;
2992
+ const record = option;
2987
2993
  const maybeValue = record[valueKey];
2988
- return {
2989
- label: typeof maybeLabel === "string" ? maybeLabel : String(maybeLabel ?? ""),
2990
- value: typeof maybeValue === "string" ? maybeValue : String(maybeValue ?? ""),
2991
- disabled: Boolean(option.disabled)
2992
- };
2993
- });
2994
- }, [options, labelKey, valueKey]);
2994
+ if (maybeValue !== void 0 && maybeValue !== null) {
2995
+ return String(maybeValue);
2996
+ }
2997
+ return getOptionLabel(option);
2998
+ },
2999
+ [valueKey, getOptionLabel]
3000
+ );
3001
+ const normalizedOptions = React30.useMemo(
3002
+ () => (options ?? []).map((option) => ({
3003
+ raw: option,
3004
+ label: getOptionLabel(option),
3005
+ value: getOptionValue(option),
3006
+ disabled: Boolean(option.disabled)
3007
+ })),
3008
+ [options, getOptionLabel, getOptionValue]
3009
+ );
2995
3010
  const [open, setOpen] = React30.useState(false);
2996
3011
  const [internalSearch, setInternalSearch] = React30.useState("");
2997
3012
  const containerRef = React30.useRef(null);
@@ -3011,13 +3026,16 @@ var Combobox = React30.forwardRef(
3011
3026
  );
3012
3027
  }, [normalizedOptions, search]);
3013
3028
  const selectedOptions = isMultiple ? multiValue : [];
3029
+ const selectedValueKeys = React30.useMemo(
3030
+ () => new Set(selectedOptions.map((option) => getOptionValue(option))),
3031
+ [selectedOptions, getOptionValue]
3032
+ );
3033
+ const singleValueKey = singleValue ? getOptionValue(singleValue) : null;
3014
3034
  const selectableOptions = React30.useMemo(
3015
3035
  () => normalizedOptions.filter((option) => !option.disabled),
3016
3036
  [normalizedOptions]
3017
3037
  );
3018
- const allSelected = isMultiple && selectableOptions.length > 0 && selectableOptions.every(
3019
- (option) => multiValue.some((item) => item.value === option.value)
3020
- );
3038
+ const allSelected = isMultiple && selectableOptions.length > 0 && selectableOptions.every((option) => selectedValueKeys.has(option.value));
3021
3039
  const handleSingleSelect = (option) => {
3022
3040
  if (!isMultiple) {
3023
3041
  if (props.value === void 0) {
@@ -3032,8 +3050,9 @@ var Combobox = React30.forwardRef(
3032
3050
  };
3033
3051
  const handleMultiSelect = (option) => {
3034
3052
  if (isMultiple) {
3035
- const exists = multiValue.some((item) => item.value === option.value);
3036
- const newValue = exists ? multiValue.filter((item) => item.value !== option.value) : [...multiValue, option];
3053
+ const optionKey = getOptionValue(option);
3054
+ const exists = multiValue.some((item) => getOptionValue(item) === optionKey);
3055
+ const newValue = exists ? multiValue.filter((item) => getOptionValue(item) !== optionKey) : [...multiValue, option];
3037
3056
  if (props.value === void 0) {
3038
3057
  setInternalMultiValue(newValue);
3039
3058
  }
@@ -3043,7 +3062,7 @@ var Combobox = React30.forwardRef(
3043
3062
  const handleRemoveItem = (optionValue, e) => {
3044
3063
  e.stopPropagation();
3045
3064
  if (isMultiple) {
3046
- const newValue = multiValue.filter((v) => v.value !== optionValue);
3065
+ const newValue = multiValue.filter((v) => getOptionValue(v) !== optionValue);
3047
3066
  if (props.value === void 0) {
3048
3067
  setInternalMultiValue(newValue);
3049
3068
  }
@@ -3064,9 +3083,9 @@ var Combobox = React30.forwardRef(
3064
3083
  if (!isMultiple) return;
3065
3084
  const nextValue = allSelected ? [] : selectableOptions;
3066
3085
  if (props.value === void 0) {
3067
- setInternalMultiValue(nextValue);
3086
+ setInternalMultiValue(nextValue.map((option) => option.raw));
3068
3087
  }
3069
- props.onChange?.(nextValue);
3088
+ props.onChange?.(nextValue.map((option) => option.raw));
3070
3089
  };
3071
3090
  const handleClearSingle = (e) => {
3072
3091
  e.stopPropagation();
@@ -3129,12 +3148,12 @@ var Combobox = React30.forwardRef(
3129
3148
  {
3130
3149
  className: "inline-flex items-center gap-1 rounded-md bg-muted px-2 py-0.5 text-xs font-medium",
3131
3150
  children: [
3132
- option.label,
3151
+ getOptionLabel(option),
3133
3152
  /* @__PURE__ */ jsx30(
3134
3153
  "button",
3135
3154
  {
3136
3155
  type: "button",
3137
- onClick: (e) => handleRemoveItem(option.value, e),
3156
+ onClick: (e) => handleRemoveItem(getOptionValue(option), e),
3138
3157
  className: "ml-1 rounded-full hover:bg-background/50",
3139
3158
  children: /* @__PURE__ */ jsx30(
3140
3159
  "svg",
@@ -3155,14 +3174,14 @@ var Combobox = React30.forwardRef(
3155
3174
  )
3156
3175
  ]
3157
3176
  },
3158
- option.value
3177
+ getOptionValue(option)
3159
3178
  )),
3160
3179
  remainingCount > 0 && /* @__PURE__ */ jsxs15("span", { className: "text-xs text-muted-foreground", children: [
3161
3180
  "+",
3162
3181
  remainingCount,
3163
3182
  " more"
3164
3183
  ] })
3165
- ] }) }) : /* @__PURE__ */ jsx30("span", { className: cn(!singleValue && "text-muted-foreground"), children: singleValue?.label ?? placeholder }),
3184
+ ] }) }) : /* @__PURE__ */ jsx30("span", { className: cn(!singleValue && "text-muted-foreground"), children: singleValue ? getOptionLabel(singleValue) : placeholder }),
3166
3185
  /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1", children: [
3167
3186
  isMultiple && selectedOptions.length > 0 && /* @__PURE__ */ jsx30(
3168
3187
  "button",
@@ -3319,13 +3338,13 @@ var Combobox = React30.forwardRef(
3319
3338
  }
3320
3339
  ),
3321
3340
  filteredOptions.map((option) => {
3322
- const isSelected = isMultiple ? multiValue.some((item) => item.value === option.value) : option.value === singleValue?.value;
3341
+ const isSelected = isMultiple ? selectedValueKeys.has(option.value) : option.value === singleValueKey;
3323
3342
  return /* @__PURE__ */ jsxs15(
3324
3343
  "button",
3325
3344
  {
3326
3345
  type: "button",
3327
3346
  disabled: option.disabled,
3328
- onClick: () => isMultiple ? handleMultiSelect(option) : handleSingleSelect(option),
3347
+ onClick: () => isMultiple ? handleMultiSelect(option.raw) : handleSingleSelect(option.raw),
3329
3348
  className: cn(
3330
3349
  "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
3331
3350
  "hover:bg-muted hover:text-foreground",
@@ -5933,7 +5952,9 @@ var PlaygroundContent = () => {
5933
5952
  {
5934
5953
  options: comboboxOptions,
5935
5954
  value: comboboxValue,
5936
- onChange: setComboboxValue,
5955
+ onChange: (nextValue) => {
5956
+ setComboboxValue(nextValue);
5957
+ },
5937
5958
  placeholder: "Search frameworks..."
5938
5959
  }
5939
5960
  )