@vellira-ui/core 2.30.0 → 2.32.0

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.
@@ -3,20 +3,28 @@ export interface SelectOptionLike extends NavigableItem {
3
3
  label: string;
4
4
  value: string;
5
5
  }
6
+ export type SelectStateValue = string | string[];
6
7
  export interface UseSelectParams<TOption extends SelectOptionLike> {
7
- value?: string;
8
- defaultValue?: string;
9
- onChange?: (value: string) => void;
8
+ value?: SelectStateValue;
9
+ defaultValue?: SelectStateValue;
10
+ onValueChange?: (value: SelectStateValue) => void;
11
+ /** @deprecated Use onValueChange. */
12
+ onChange?: (value: SelectStateValue) => void;
10
13
  options: TOption[];
14
+ multiple?: boolean;
15
+ maxSelected?: number;
16
+ closeOnSelect?: boolean;
11
17
  disabled?: boolean;
12
18
  open?: boolean;
13
19
  defaultOpen?: boolean;
14
20
  onOpenChange?: (open: boolean) => void;
15
21
  }
16
- export declare const useSelect: <TOption extends SelectOptionLike>({ value, defaultValue, onChange, options, disabled, open, defaultOpen, onOpenChange, }: UseSelectParams<TOption>) => {
17
- selectedValue: string;
18
- setSelectedValue: (next: string) => void;
22
+ export declare const useSelect: <TOption extends SelectOptionLike>({ value, defaultValue, onValueChange, onChange, options, multiple, maxSelected, closeOnSelect, disabled, open, defaultOpen, onOpenChange, }: UseSelectParams<TOption>) => {
23
+ selectedValue: SelectStateValue;
24
+ selectedValues: string[];
25
+ setSelectedValue: (next: SelectStateValue) => void;
19
26
  selectedOption: TOption | undefined;
27
+ selectedOptions: TOption[];
20
28
  isOpen: boolean;
21
29
  open: boolean;
22
30
  setIsOpen: (next: boolean) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useSelect.d.ts","sourceRoot":"","sources":["../src/useSelect.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,gBAAgB;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,gBAAgB,EAAE,wFASzD,eAAe,CAAC,OAAO,CAAC;;;;;;;;;;;;;6BAoDX,MAAM;wBAAN,MAAM;;;CAgDrB,CAAC"}
1
+ {"version":3,"file":"useSelect.d.ts","sourceRoot":"","sources":["../src/useSelect.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAEjD,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,gBAAgB;IAC/D,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,qCAAqC;IACrC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7C,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,gBAAgB,EAAE,6IAazD,eAAe,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;6BAmEX,MAAM;wBAAN,MAAM;;;CAsFrB,CAAC"}
package/dist/useSelect.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { useCallback, useMemo, useState } from 'react';
2
2
  import { useControllableState } from './useControllableState.js';
3
3
  import { useKeyboardNavigation, } from './useKeyboardNavigation.js';
4
- export const useSelect = ({ value, defaultValue, onChange, options, disabled = false, open, defaultOpen = false, onOpenChange, }) => {
4
+ export const useSelect = ({ value, defaultValue, onValueChange, onChange, options, multiple = false, maxSelected, closeOnSelect = !multiple, disabled = false, open, defaultOpen = false, onOpenChange, }) => {
5
5
  const [selectedValue, setSelectedValue] = useControllableState({
6
6
  value,
7
- defaultValue: defaultValue ?? '',
8
- onChange,
7
+ defaultValue: defaultValue ?? (multiple ? [] : ''),
8
+ onChange: onValueChange ?? onChange,
9
9
  });
10
10
  const [isOpen, setIsOpen] = useControllableState({
11
11
  value: open,
@@ -13,13 +13,19 @@ export const useSelect = ({ value, defaultValue, onChange, options, disabled = f
13
13
  onChange: onOpenChange,
14
14
  });
15
15
  const [activeIndex, setActiveIndex] = useState(-1);
16
- const selectedOption = useMemo(() => options.find((option) => option.value === selectedValue), [options, selectedValue]);
16
+ const selectedValues = useMemo(() => Array.isArray(selectedValue)
17
+ ? selectedValue
18
+ : selectedValue
19
+ ? [selectedValue]
20
+ : [], [selectedValue]);
21
+ const selectedOption = useMemo(() => options.find((option) => selectedValues.includes(option.value)), [options, selectedValues]);
22
+ const selectedOptions = useMemo(() => options.filter((option) => selectedValues.includes(option.value)), [options, selectedValues]);
17
23
  const getInitialActiveIndex = useCallback(() => {
18
- const selectedIndex = options.findIndex((option) => option.value === selectedValue && !option.disabled);
24
+ const selectedIndex = options.findIndex((option) => selectedValues.includes(option.value) && !option.disabled);
19
25
  if (selectedIndex >= 0)
20
26
  return selectedIndex;
21
27
  return options.findIndex((option) => !option.disabled);
22
- }, [options, selectedValue]);
28
+ }, [options, selectedValues]);
23
29
  const openDropdown = useCallback(() => {
24
30
  if (disabled)
25
31
  return;
@@ -39,12 +45,41 @@ export const useSelect = ({ value, defaultValue, onChange, options, disabled = f
39
45
  openDropdown();
40
46
  }, [closeDropdown, disabled, isOpen, openDropdown]);
41
47
  const selectValue = useCallback((nextValue) => {
48
+ if (nextValue === '') {
49
+ setSelectedValue(multiple ? [] : '');
50
+ closeDropdown();
51
+ return;
52
+ }
42
53
  const nextOption = options.find((option) => option.value === nextValue);
43
54
  if (!nextOption || nextOption.disabled)
44
55
  return;
56
+ if (multiple) {
57
+ const isSelected = selectedValues.includes(nextValue);
58
+ if (!isSelected &&
59
+ typeof maxSelected === 'number' &&
60
+ selectedValues.length >= maxSelected) {
61
+ return;
62
+ }
63
+ const nextValues = selectedValues.includes(nextValue)
64
+ ? selectedValues.filter((value) => value !== nextValue)
65
+ : [...selectedValues, nextValue];
66
+ setSelectedValue(nextValues);
67
+ if (closeOnSelect) {
68
+ closeDropdown();
69
+ }
70
+ return;
71
+ }
45
72
  setSelectedValue(nextValue);
46
73
  closeDropdown();
47
- }, [closeDropdown, options, setSelectedValue]);
74
+ }, [
75
+ closeDropdown,
76
+ closeOnSelect,
77
+ maxSelected,
78
+ multiple,
79
+ options,
80
+ selectedValues,
81
+ setSelectedValue,
82
+ ]);
48
83
  const selectActiveOption = useCallback(() => {
49
84
  const activeOption = options[activeIndex];
50
85
  if (!activeOption)
@@ -63,8 +98,10 @@ export const useSelect = ({ value, defaultValue, onChange, options, disabled = f
63
98
  });
64
99
  return {
65
100
  selectedValue,
101
+ selectedValues,
66
102
  setSelectedValue,
67
103
  selectedOption,
104
+ selectedOptions,
68
105
  isOpen,
69
106
  open: isOpen,
70
107
  setIsOpen,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/core",
3
- "version": "2.30.0",
3
+ "version": "2.32.0",
4
4
  "description": "Shared logic and hooks for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",