@onesaz/ui 0.3.4 → 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 +20 -11
- package/dist/index.js +58 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -678,11 +678,14 @@ interface ComboboxOption {
|
|
|
678
678
|
label: string;
|
|
679
679
|
disabled?: boolean;
|
|
680
680
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
681
|
+
type ComboboxPrimitiveOption = string;
|
|
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;
|
|
686
689
|
placeholder?: string;
|
|
687
690
|
searchPlaceholder?: string;
|
|
688
691
|
emptyMessage?: string;
|
|
@@ -693,12 +696,15 @@ interface ComboboxSingleProps {
|
|
|
693
696
|
openOnFocus?: boolean;
|
|
694
697
|
inputValue?: string;
|
|
695
698
|
onInputChange?: (value: string) => void;
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
699
|
+
simpleOptions?: boolean;
|
|
700
|
+
labelKey?: string;
|
|
701
|
+
valueKey?: string;
|
|
702
|
+
}
|
|
703
|
+
interface ComboboxMultipleProps<T extends ComboboxOptionInput = ComboboxOptionInput> {
|
|
704
|
+
options: T[];
|
|
705
|
+
value?: T[];
|
|
706
|
+
defaultValue?: T[];
|
|
707
|
+
onChange?: (value: T[]) => void;
|
|
702
708
|
placeholder?: string;
|
|
703
709
|
searchPlaceholder?: string;
|
|
704
710
|
emptyMessage?: string;
|
|
@@ -713,6 +719,9 @@ interface ComboboxMultipleProps {
|
|
|
713
719
|
selectAll?: boolean;
|
|
714
720
|
/** Label for select-all option */
|
|
715
721
|
selectAllLabel?: string;
|
|
722
|
+
simpleOptions?: boolean;
|
|
723
|
+
labelKey?: string;
|
|
724
|
+
valueKey?: string;
|
|
716
725
|
/** Maximum number of items to display as chips before showing "+N more" */
|
|
717
726
|
maxDisplayItems?: number;
|
|
718
727
|
}
|
package/dist/index.js
CHANGED
|
@@ -2975,6 +2975,38 @@ var Combobox = React30.forwardRef(
|
|
|
2975
2975
|
openOnFocus = true,
|
|
2976
2976
|
className
|
|
2977
2977
|
} = props;
|
|
2978
|
+
const labelKey = props.labelKey ?? "label";
|
|
2979
|
+
const valueKey = props.valueKey ?? "value";
|
|
2980
|
+
const getOptionLabel = React30.useCallback(
|
|
2981
|
+
(option) => {
|
|
2982
|
+
if (typeof option === "string") return option;
|
|
2983
|
+
const record = option;
|
|
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;
|
|
2993
|
+
const maybeValue = record[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
|
+
);
|
|
2978
3010
|
const [open, setOpen] = React30.useState(false);
|
|
2979
3011
|
const [internalSearch, setInternalSearch] = React30.useState("");
|
|
2980
3012
|
const containerRef = React30.useRef(null);
|
|
@@ -2988,19 +3020,22 @@ var Combobox = React30.forwardRef(
|
|
|
2988
3020
|
const multiValue = isMultiple ? props.value !== void 0 ? props.value : internalMultiValue : [];
|
|
2989
3021
|
const search = props.inputValue !== void 0 ? props.inputValue : internalSearch;
|
|
2990
3022
|
const filteredOptions = React30.useMemo(() => {
|
|
2991
|
-
if (!search) return
|
|
2992
|
-
return
|
|
3023
|
+
if (!search) return normalizedOptions;
|
|
3024
|
+
return normalizedOptions.filter(
|
|
2993
3025
|
(option) => option.label.toLowerCase().includes(search.toLowerCase())
|
|
2994
3026
|
);
|
|
2995
|
-
}, [
|
|
3027
|
+
}, [normalizedOptions, search]);
|
|
2996
3028
|
const selectedOptions = isMultiple ? multiValue : [];
|
|
2997
|
-
const
|
|
2998
|
-
() =>
|
|
2999
|
-
[
|
|
3029
|
+
const selectedValueKeys = React30.useMemo(
|
|
3030
|
+
() => new Set(selectedOptions.map((option) => getOptionValue(option))),
|
|
3031
|
+
[selectedOptions, getOptionValue]
|
|
3000
3032
|
);
|
|
3001
|
-
const
|
|
3002
|
-
|
|
3033
|
+
const singleValueKey = singleValue ? getOptionValue(singleValue) : null;
|
|
3034
|
+
const selectableOptions = React30.useMemo(
|
|
3035
|
+
() => normalizedOptions.filter((option) => !option.disabled),
|
|
3036
|
+
[normalizedOptions]
|
|
3003
3037
|
);
|
|
3038
|
+
const allSelected = isMultiple && selectableOptions.length > 0 && selectableOptions.every((option) => selectedValueKeys.has(option.value));
|
|
3004
3039
|
const handleSingleSelect = (option) => {
|
|
3005
3040
|
if (!isMultiple) {
|
|
3006
3041
|
if (props.value === void 0) {
|
|
@@ -3015,8 +3050,9 @@ var Combobox = React30.forwardRef(
|
|
|
3015
3050
|
};
|
|
3016
3051
|
const handleMultiSelect = (option) => {
|
|
3017
3052
|
if (isMultiple) {
|
|
3018
|
-
const
|
|
3019
|
-
const
|
|
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];
|
|
3020
3056
|
if (props.value === void 0) {
|
|
3021
3057
|
setInternalMultiValue(newValue);
|
|
3022
3058
|
}
|
|
@@ -3026,7 +3062,7 @@ var Combobox = React30.forwardRef(
|
|
|
3026
3062
|
const handleRemoveItem = (optionValue, e) => {
|
|
3027
3063
|
e.stopPropagation();
|
|
3028
3064
|
if (isMultiple) {
|
|
3029
|
-
const newValue = multiValue.filter((v) => v
|
|
3065
|
+
const newValue = multiValue.filter((v) => getOptionValue(v) !== optionValue);
|
|
3030
3066
|
if (props.value === void 0) {
|
|
3031
3067
|
setInternalMultiValue(newValue);
|
|
3032
3068
|
}
|
|
@@ -3047,9 +3083,9 @@ var Combobox = React30.forwardRef(
|
|
|
3047
3083
|
if (!isMultiple) return;
|
|
3048
3084
|
const nextValue = allSelected ? [] : selectableOptions;
|
|
3049
3085
|
if (props.value === void 0) {
|
|
3050
|
-
setInternalMultiValue(nextValue);
|
|
3086
|
+
setInternalMultiValue(nextValue.map((option) => option.raw));
|
|
3051
3087
|
}
|
|
3052
|
-
props.onChange?.(nextValue);
|
|
3088
|
+
props.onChange?.(nextValue.map((option) => option.raw));
|
|
3053
3089
|
};
|
|
3054
3090
|
const handleClearSingle = (e) => {
|
|
3055
3091
|
e.stopPropagation();
|
|
@@ -3112,12 +3148,12 @@ var Combobox = React30.forwardRef(
|
|
|
3112
3148
|
{
|
|
3113
3149
|
className: "inline-flex items-center gap-1 rounded-md bg-muted px-2 py-0.5 text-xs font-medium",
|
|
3114
3150
|
children: [
|
|
3115
|
-
option
|
|
3151
|
+
getOptionLabel(option),
|
|
3116
3152
|
/* @__PURE__ */ jsx30(
|
|
3117
3153
|
"button",
|
|
3118
3154
|
{
|
|
3119
3155
|
type: "button",
|
|
3120
|
-
onClick: (e) => handleRemoveItem(option
|
|
3156
|
+
onClick: (e) => handleRemoveItem(getOptionValue(option), e),
|
|
3121
3157
|
className: "ml-1 rounded-full hover:bg-background/50",
|
|
3122
3158
|
children: /* @__PURE__ */ jsx30(
|
|
3123
3159
|
"svg",
|
|
@@ -3138,14 +3174,14 @@ var Combobox = React30.forwardRef(
|
|
|
3138
3174
|
)
|
|
3139
3175
|
]
|
|
3140
3176
|
},
|
|
3141
|
-
option
|
|
3177
|
+
getOptionValue(option)
|
|
3142
3178
|
)),
|
|
3143
3179
|
remainingCount > 0 && /* @__PURE__ */ jsxs15("span", { className: "text-xs text-muted-foreground", children: [
|
|
3144
3180
|
"+",
|
|
3145
3181
|
remainingCount,
|
|
3146
3182
|
" more"
|
|
3147
3183
|
] })
|
|
3148
|
-
] }) }) : /* @__PURE__ */ jsx30("span", { className: cn(!singleValue && "text-muted-foreground"), children: singleValue
|
|
3184
|
+
] }) }) : /* @__PURE__ */ jsx30("span", { className: cn(!singleValue && "text-muted-foreground"), children: singleValue ? getOptionLabel(singleValue) : placeholder }),
|
|
3149
3185
|
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1", children: [
|
|
3150
3186
|
isMultiple && selectedOptions.length > 0 && /* @__PURE__ */ jsx30(
|
|
3151
3187
|
"button",
|
|
@@ -3302,13 +3338,13 @@ var Combobox = React30.forwardRef(
|
|
|
3302
3338
|
}
|
|
3303
3339
|
),
|
|
3304
3340
|
filteredOptions.map((option) => {
|
|
3305
|
-
const isSelected = isMultiple ?
|
|
3341
|
+
const isSelected = isMultiple ? selectedValueKeys.has(option.value) : option.value === singleValueKey;
|
|
3306
3342
|
return /* @__PURE__ */ jsxs15(
|
|
3307
3343
|
"button",
|
|
3308
3344
|
{
|
|
3309
3345
|
type: "button",
|
|
3310
3346
|
disabled: option.disabled,
|
|
3311
|
-
onClick: () => isMultiple ? handleMultiSelect(option) : handleSingleSelect(option),
|
|
3347
|
+
onClick: () => isMultiple ? handleMultiSelect(option.raw) : handleSingleSelect(option.raw),
|
|
3312
3348
|
className: cn(
|
|
3313
3349
|
"relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
|
|
3314
3350
|
"hover:bg-muted hover:text-foreground",
|
|
@@ -5916,7 +5952,9 @@ var PlaygroundContent = () => {
|
|
|
5916
5952
|
{
|
|
5917
5953
|
options: comboboxOptions,
|
|
5918
5954
|
value: comboboxValue,
|
|
5919
|
-
onChange:
|
|
5955
|
+
onChange: (nextValue) => {
|
|
5956
|
+
setComboboxValue(nextValue);
|
|
5957
|
+
},
|
|
5920
5958
|
placeholder: "Search frameworks..."
|
|
5921
5959
|
}
|
|
5922
5960
|
)
|