@rescui/select 0.15.2 → 0.16.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.
Files changed (95) hide show
  1. package/lib/_virtual/index.css.js +12 -12
  2. package/lib/common-prop-types.d.ts +8 -14
  3. package/lib/common-prop-types.js +4 -3
  4. package/lib/constants.d.ts +6 -0
  5. package/lib/constants.js +7 -0
  6. package/lib/hooks/use-a11y.d.ts +30 -0
  7. package/lib/hooks/use-a11y.js +56 -0
  8. package/lib/hooks/use-actual-size-from-css.d.ts +10 -0
  9. package/lib/hooks/use-actual-size-from-css.js +27 -0
  10. package/lib/hooks/use-focus.d.ts +10 -0
  11. package/lib/hooks/use-focus.js +17 -0
  12. package/lib/hooks/use-hover.d.ts +10 -0
  13. package/lib/hooks/use-hover.js +17 -0
  14. package/lib/hooks/use-label-focus.d.ts +9 -0
  15. package/lib/hooks/use-label-focus.js +22 -0
  16. package/lib/hooks/use-multi-handlers.d.ts +11 -0
  17. package/lib/hooks/use-multi-handlers.js +44 -0
  18. package/lib/hooks/use-options.d.ts +14 -0
  19. package/lib/hooks/use-options.js +90 -0
  20. package/lib/hooks/use-primary-contrast-css-var-transfer.d.ts +11 -0
  21. package/lib/hooks/use-primary-contrast-css-var-transfer.js +29 -0
  22. package/lib/hooks/use-safe-id.d.ts +6 -0
  23. package/lib/hooks/use-safe-id.js +15 -0
  24. package/lib/index.css +713 -304
  25. package/lib/index.d.ts +4 -6
  26. package/lib/index.js +3 -3
  27. package/lib/multiselect.d.ts +3 -0
  28. package/lib/multiselect.js +308 -0
  29. package/lib/native-select.d.ts +4 -0
  30. package/lib/native-select.js +208 -0
  31. package/lib/parts/foldable.js +1 -2
  32. package/lib/parts/form-trigger-wrapper.d.ts +7 -7
  33. package/lib/parts/form-trigger-wrapper.js +16 -34
  34. package/lib/parts/hidden-select.d.ts +13 -0
  35. package/lib/parts/hidden-select.js +45 -0
  36. package/lib/parts/icons.d.ts +17 -0
  37. package/lib/parts/icons.js +69 -0
  38. package/lib/parts/list-box.d.ts +13 -0
  39. package/lib/parts/list-box.js +120 -0
  40. package/lib/parts/multi-trigger.d.ts +12 -0
  41. package/lib/parts/multi-trigger.js +70 -0
  42. package/lib/parts/native-select-options-with-groups.d.ts +8 -0
  43. package/lib/parts/native-select-options-with-groups.js +76 -0
  44. package/lib/parts/popup-content.d.ts +20 -0
  45. package/lib/parts/popup-content.js +68 -0
  46. package/lib/public-api.p.css +543 -307
  47. package/lib/public-api.pcss +543 -307
  48. package/lib/select-basic.d.ts +3 -0
  49. package/lib/select-basic.js +204 -0
  50. package/lib/select-searchable.d.ts +3 -0
  51. package/lib/select-searchable.js +245 -0
  52. package/lib/select.d.ts +27 -91
  53. package/lib/select.js +51 -351
  54. package/lib/styles/common.p.module.css.js +32 -0
  55. package/lib/styles/form-trigger.p.module.css.js +15 -0
  56. package/lib/styles/list-box.p.module.css.js +16 -0
  57. package/lib/types.d.ts +172 -4
  58. package/lib/utils/calculate-max-height-by-items.d.ts +13 -0
  59. package/lib/utils/calculate-max-height-by-items.js +22 -0
  60. package/lib/utils/get-empty-message.d.ts +6 -0
  61. package/lib/utils/get-empty-message.js +32 -0
  62. package/lib/utils/get-option-value.d.ts +2 -0
  63. package/lib/utils/get-option-value.js +11 -0
  64. package/lib/utils/get-real-items-cnt.d.ts +2 -0
  65. package/lib/utils/get-real-items-cnt.js +19 -0
  66. package/lib/utils/get-text-from-nodes.d.ts +2 -0
  67. package/lib/utils/get-text-from-nodes.js +26 -0
  68. package/lib/utils/is-option-a-group.d.ts +2 -0
  69. package/lib/utils/is-option-a-group.js +5 -0
  70. package/lib/utils/item-to-string.d.ts +2 -0
  71. package/lib/utils/item-to-string.js +7 -0
  72. package/lib/utils/merge-props.d.ts +19 -0
  73. package/lib/utils/merge-props.js +104 -0
  74. package/lib/utils/throttle.d.ts +1 -0
  75. package/package.json +6 -6
  76. package/lib/key-codes.d.ts +0 -7
  77. package/lib/key-codes.js +0 -8
  78. package/lib/parts/common-select.p.module.css.js +0 -15
  79. package/lib/parts/form-trigger.p.module.css.js +0 -15
  80. package/lib/parts/multiselect.d.ts +0 -86
  81. package/lib/parts/multiselect.js +0 -455
  82. package/lib/parts/native-select.d.ts +0 -36
  83. package/lib/parts/native-select.js +0 -255
  84. package/lib/parts/native-select.p.module.css.js +0 -9
  85. package/lib/parts/throttle.d.ts +0 -1
  86. package/lib/parts/trigger.d.ts +0 -37
  87. package/lib/parts/trigger.js +0 -255
  88. package/lib/parts/trigger.p.module.css.js +0 -31
  89. package/lib/parts/use-backward-compatible-id.d.ts +0 -4
  90. package/lib/parts/use-backward-compatible-id.js +0 -14
  91. package/lib/parts/use-observable-force-rerender.d.ts +0 -2
  92. package/lib/parts/use-observable-force-rerender.js +0 -16
  93. package/lib/utils.d.ts +0 -22
  94. package/lib/utils.js +0 -199
  95. /package/lib/{parts → utils}/throttle.js +0 -0
package/lib/types.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  import React from 'react';
2
+ import type { Theme } from '@rescui/ui-contexts';
3
+ import type { UseSelectPropGetters } from 'downshift';
4
+ export declare type Key = string | number;
5
+ export declare type Placement = 'auto-start' | 'auto' | 'auto-end' | 'top-start' | 'top' | 'top-end' | 'right-start' | 'right' | 'right-end' | 'bottom-end' | 'bottom' | 'bottom-start' | 'left-end' | 'left' | 'left-start';
2
6
  export declare type SelectSize = 'l' | 'm' | 's';
3
7
  export declare type SelectMode = 'classic' | 'rock';
4
8
  export declare type SelectOption = {
5
9
  label: React.ReactNode;
6
- value?: string;
10
+ value?: Key;
7
11
  };
8
12
  export declare type SelectOptionsGroup = {
9
13
  label?: React.ReactNode;
@@ -11,9 +15,29 @@ export declare type SelectOptionsGroup = {
11
15
  };
12
16
  export declare type SelectOptionOrGroup = SelectOption | SelectOptionsGroup;
13
17
  export declare type SelectOptions = SelectOptionOrGroup[];
18
+ export declare type ListBoxOptionItem = SelectOption & {
19
+ index: number;
20
+ type: 'option';
21
+ key: Key;
22
+ disabled?: boolean;
23
+ };
24
+ export declare type ListBoxGroupItem = Omit<SelectOptionsGroup, 'options'> & {
25
+ options: ListBoxOptionItem[];
26
+ type: 'group';
27
+ key: Key;
28
+ };
29
+ export declare type ListBoxItem = ListBoxOptionItem | ListBoxGroupItem;
30
+ export declare type ListBoxItems = ListBoxItem[];
31
+ export declare type ListBoxState = {
32
+ menuProps: ReturnType<UseSelectPropGetters<SelectOption>['getMenuProps']>;
33
+ getItemProps: UseSelectPropGetters<SelectOption>['getItemProps'];
34
+ highlightedIndex: number;
35
+ selectedMap: Map<Key, SelectOption>;
36
+ menuRef?: React.RefObject<HTMLUListElement>;
37
+ };
14
38
  export declare type NativeSelectOption = {
15
39
  label: string;
16
- value?: string;
40
+ value?: Key;
17
41
  disabled?: boolean;
18
42
  };
19
43
  export declare type NativeSelectOptionsGroup = {
@@ -24,11 +48,155 @@ export declare type NativeSelectOptionsGroup = {
24
48
  export declare type NativeSelectOptionOrGroup = NativeSelectOption | NativeSelectOptionsGroup;
25
49
  export declare type NativeSelectOptions = NativeSelectOptionOrGroup[];
26
50
  export declare type Groups = SelectOptionsGroup[];
27
- export declare type Index = [number, number];
28
- export declare type FilterFn = (option: SelectOption) => boolean;
29
51
  export declare type NoOptionsMessageConfig = {
30
52
  noOptions: string;
31
53
  nothingFound?: string;
32
54
  loading?: string;
33
55
  };
34
56
  export declare type NoOptionsMessage = string | NoOptionsMessageConfig;
57
+ export declare type SelectProps = {
58
+ /**
59
+ * Value of the select
60
+ */
61
+ value?: SelectOption | null;
62
+ /**
63
+ * Change value callback. `value => ...`. Pass `null` on clear.
64
+ */
65
+ onChange?: (newValue: SelectOption | null) => void;
66
+ /**
67
+ * Additional class name
68
+ */
69
+ className?: string;
70
+ style?: React.CSSProperties;
71
+ id?: string;
72
+ /**
73
+ * Array of options or option groups
74
+ */
75
+ options?: (SelectOption | SelectOptionsGroup)[] | null;
76
+ /**
77
+ * Is select supports clearing the value
78
+ */
79
+ isClearable?: boolean;
80
+ /**
81
+ * Is select supports inplace filtering
82
+ */
83
+ isSearchable?: boolean;
84
+ /**
85
+ * Is the component has been disabled
86
+ */
87
+ isDisabled?: boolean;
88
+ /**
89
+ * Is loader displayed inside the trigger part
90
+ */
91
+ isLoading?: boolean;
92
+ /**
93
+ * A hint to the user of what can be entered in the control
94
+ */
95
+ placeholder?: string;
96
+ /**
97
+ * Size
98
+ */
99
+ size?: SelectSize;
100
+ /**
101
+ * Appearance mode
102
+ */
103
+ mode?: SelectMode;
104
+ /**
105
+ * Appearance theme
106
+ */
107
+ theme?: Theme;
108
+ /**
109
+ * Error state flag or `React.ReactNode` (use with forms)
110
+ */
111
+ error?: boolean | React.ReactNode;
112
+ /**
113
+ * If `true`, there will be reserved a space for a 1-line error message. Subsequent lines will be placed below normally.
114
+ * If `false`, there will be no reservation.
115
+ */
116
+ reserveErrorLine?: boolean;
117
+ /**
118
+ * Label element (use with forms)
119
+ */
120
+ label?: React.ReactNode;
121
+ /**
122
+ * If `true`, label will be bold
123
+ */
124
+ boldLabel?: boolean;
125
+ /**
126
+ * Placement of dropdown element
127
+ */
128
+ placement?: Placement;
129
+ /**
130
+ * Note element at the bottom (use with forms)
131
+ */
132
+ note?: React.ReactNode;
133
+ /**
134
+ * Text to display when there are no options
135
+ */
136
+ noOptionsMessage?: NoOptionsMessage;
137
+ /**
138
+ * Input name attribute
139
+ */
140
+ name?: string;
141
+ /**
142
+ * Maximum number of fully visible items in the dropdown list.
143
+ * For large lists, `n + 0.5` items will be visible at a time.
144
+ * If the maximum number of items in a list is exactly `n + 1`, all
145
+ * items will be shown instead (to avoid creating a scroll for half an item only).
146
+ */
147
+ maxVisibleItems?: number;
148
+ };
149
+ export declare type MultiselectProps = {
150
+ /**
151
+ * Value of the multiselect (array of selected options)
152
+ */
153
+ value?: SelectOption[] | null;
154
+ /**
155
+ * Change value callback. `value => ...`. Pass `[]` on clear.
156
+ */
157
+ onChange?: (newValue: SelectOption[]) => void;
158
+ /**
159
+ * Display tags in single line with "+N" counter
160
+ */
161
+ isSingleLine?: boolean;
162
+ } & Omit<SelectProps, 'value' | 'onChange' | 'isSearchable'>;
163
+ export declare type TriggerFuncProps = {
164
+ selectedLabel?: string;
165
+ selectedValue?: Key;
166
+ placeholder?: string;
167
+ hovered: boolean;
168
+ focused: boolean;
169
+ };
170
+ export declare type NativeSelectProps = {
171
+ options?: (NativeSelectOption | NativeSelectOptionsGroup)[];
172
+ size?: SelectSize;
173
+ theme?: Theme;
174
+ className?: string;
175
+ id?: string;
176
+ style?: React.CSSProperties;
177
+ value?: NativeSelectOption | null;
178
+ onChange?: (newValue: NativeSelectOption | null) => void;
179
+ placeholder?: string;
180
+ isLoading?: boolean;
181
+ isDisabled?: boolean;
182
+ isClearable?: boolean;
183
+ trigger?: (props: TriggerFuncProps) => React.ReactNode;
184
+ label?: React.ReactNode;
185
+ note?: React.ReactNode;
186
+ error?: boolean | React.ReactNode;
187
+ /**
188
+ * If `true`, there will be reserved a space for a 1-line error message. Subsequent lines will be placed below normally.
189
+ * If `false`, there will be no reservation.
190
+ */
191
+ reserveErrorLine?: boolean;
192
+ noOptionsMessage?: NoOptionsMessage;
193
+ name?: string;
194
+ boldLabel?: boolean;
195
+ };
196
+ export declare type InnerSingleComponentProps = Omit<SelectProps, 'isSearchable'>;
197
+ export declare type DownshiftSyntheticEvent = React.SyntheticEvent & {
198
+ preventDownshiftDefault?: boolean;
199
+ nativeEvent: {
200
+ preventDownshiftDefault?: boolean;
201
+ };
202
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Calculate the max height of the list based on items count and allowedMaxVisibleItems.
3
+ * Instead of simply adding 0.5 to the allowedMaxVisibleItems, we process
4
+ * `itemsCount == allowedMaxVisibleItems + 1` differently.
5
+ *
6
+ * For allowedMaxVisibleItems={5}:
7
+ * - If items itemsCount <= 5: restrain by 5.5 items (to avoid scrollbar due to layout shifts)
8
+ * - If items itemsCount = 6: restrain by all 6.1 items (6 + 0.1 for group separators)
9
+ * - If items itemsCount > 6: restrain by 5.5 items
10
+ *
11
+ * Formula: max(5.5, min(itemsCount + 0.1, 6.1) - min(max(0, itemsCount - 6), 0.6))
12
+ */
13
+ export declare const calculateMaxHeightByItems: (itemsCount: number, allowedMaxVisibleItems: number) => number;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Calculate the max height of the list based on items count and allowedMaxVisibleItems.
3
+ * Instead of simply adding 0.5 to the allowedMaxVisibleItems, we process
4
+ * `itemsCount == allowedMaxVisibleItems + 1` differently.
5
+ *
6
+ * For allowedMaxVisibleItems={5}:
7
+ * - If items itemsCount <= 5: restrain by 5.5 items (to avoid scrollbar due to layout shifts)
8
+ * - If items itemsCount = 6: restrain by all 6.1 items (6 + 0.1 for group separators)
9
+ * - If items itemsCount > 6: restrain by 5.5 items
10
+ *
11
+ * Formula: max(5.5, min(itemsCount + 0.1, 6.1) - min(max(0, itemsCount - 6), 0.6))
12
+ */
13
+ const calculateMaxHeightByItems = (itemsCount, allowedMaxVisibleItems) => {
14
+ const allowedFloor = Math.floor(allowedMaxVisibleItems);
15
+ const groupSeparatorsDelta = 0.1;
16
+ const partiallyVisiblePart = 0.5;
17
+ const upperLimit = Math.min(itemsCount + groupSeparatorsDelta, allowedFloor + 1 + groupSeparatorsDelta);
18
+ const delta = Math.min(Math.max(0, itemsCount - (allowedFloor + 1)), partiallyVisiblePart + groupSeparatorsDelta);
19
+ return Math.max(allowedFloor + partiallyVisiblePart, upperLimit - delta);
20
+ };
21
+
22
+ export { calculateMaxHeightByItems };
@@ -0,0 +1,6 @@
1
+ import type { NoOptionsMessage } from '../types';
2
+ export declare function getEmptyMessage({ isLoading, isNothingFound, noOptionsMessage }: {
3
+ isLoading: boolean;
4
+ isNothingFound: boolean;
5
+ noOptionsMessage: NoOptionsMessage;
6
+ }): string;
@@ -0,0 +1,32 @@
1
+ import { DEFAULT_NO_OPTIONS_MESSAGES } from '../constants.js';
2
+
3
+ function isString(s) {
4
+ return Object.prototype.toString.call(s) === '[object String]';
5
+ }
6
+
7
+ function getEmptyMessage(_ref) {
8
+ let {
9
+ isLoading,
10
+ isNothingFound,
11
+ noOptionsMessage
12
+ } = _ref;
13
+ const {
14
+ noOptions,
15
+ nothingFound,
16
+ loading
17
+ } = isString(noOptionsMessage) ? { ...DEFAULT_NO_OPTIONS_MESSAGES,
18
+ noOptions: noOptionsMessage
19
+ } : { ...DEFAULT_NO_OPTIONS_MESSAGES,
20
+ ...noOptionsMessage
21
+ };
22
+
23
+ if (isLoading) {
24
+ return loading;
25
+ } else if (isNothingFound) {
26
+ return nothingFound;
27
+ } else {
28
+ return noOptions;
29
+ }
30
+ }
31
+
32
+ export { getEmptyMessage };
@@ -0,0 +1,2 @@
1
+ import type { SelectOption, Key } from '../types';
2
+ export declare function getOptionValue(option?: SelectOption): Key | null;
@@ -0,0 +1,11 @@
1
+ import { getTextFromNodes } from './get-text-from-nodes.js';
2
+
3
+ function getOptionValue(option) {
4
+ if (!option) {
5
+ return null;
6
+ }
7
+
8
+ return typeof option.value === 'string' || typeof option.value === 'number' ? option.value : getTextFromNodes(option.label);
9
+ }
10
+
11
+ export { getOptionValue };
@@ -0,0 +1,2 @@
1
+ import { ListBoxItem } from '../types';
2
+ export declare const getRealItemsCnt: (items: ListBoxItem[]) => number;
@@ -0,0 +1,19 @@
1
+ const getRealItemsCnt = items => {
2
+ // Count total number of items
3
+ return items.reduce((count, item) => {
4
+ if (item.type === 'group') {
5
+ const groupOptions = item.options;
6
+ const hasHeading = item.label !== null && item.label !== undefined; // Count heading (if present) + all options in the section
7
+
8
+ return count + (hasHeading ? 1 : 0) + groupOptions.length;
9
+ }
10
+
11
+ if (item.type === 'option') {
12
+ return count + 1;
13
+ }
14
+
15
+ return count;
16
+ }, 0);
17
+ };
18
+
19
+ export { getRealItemsCnt };
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const getTextFromNodes: (node: React.ReactNode, depth?: number) => string;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+
3
+ const getTextFromNodes = function (node) {
4
+ let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
5
+
6
+ if (typeof node === 'string' || typeof node === 'number') {
7
+ return node.toString();
8
+ }
9
+
10
+ if (depth > 15) {
11
+ console.warn('Max depth reached while getting text from nodes');
12
+ return '';
13
+ }
14
+
15
+ if (Array.isArray(node)) {
16
+ return node.map(n => getTextFromNodes(n, depth + 1)).join('');
17
+ }
18
+
19
+ if ( /*#__PURE__*/React.isValidElement(node) && node?.type?.toString()?.toLowerCase() !== 'svg') {
20
+ return getTextFromNodes(node.props.children, depth + 1);
21
+ }
22
+
23
+ return '';
24
+ };
25
+
26
+ export { getTextFromNodes };
@@ -0,0 +1,2 @@
1
+ import type { SelectOptionOrGroup, SelectOptionsGroup, NativeSelectOptionOrGroup, NativeSelectOption } from '../types';
2
+ export declare const isOptionAGroup: (optionOrGroup: SelectOptionOrGroup | NativeSelectOptionOrGroup) => optionOrGroup is SelectOptionsGroup | NativeSelectOption;
@@ -0,0 +1,5 @@
1
+ const isOptionAGroup = optionOrGroup => {
2
+ return 'options' in optionOrGroup && typeof optionOrGroup.options !== 'undefined';
3
+ };
4
+
5
+ export { isOptionAGroup };
@@ -0,0 +1,2 @@
1
+ import type { SelectOption } from '../types';
2
+ export declare function itemToString(item: SelectOption): string;
@@ -0,0 +1,7 @@
1
+ import { getTextFromNodes } from './get-text-from-nodes.js';
2
+
3
+ function itemToString(item) {
4
+ return item ? getTextFromNodes(item.label) : '';
5
+ }
6
+
7
+ export { itemToString };
@@ -0,0 +1,19 @@
1
+ import { RefCallback } from 'react';
2
+ declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
3
+ /**
4
+ * Combines multiple sets of props into a single object:
5
+ * - conflicting `className` values are joined with a space
6
+ * - conflicting `style` objects are shallow-merged (rightmost wins on conflict)
7
+ * - conflicting function props (event handlers) are composed and called left to right
8
+ * - conflicting `ref` props (object refs, callback refs, or null) are merged into a single
9
+ * callback ref that assigns all of them; cleanup functions returned by callback refs are
10
+ * collected and called together on detach
11
+ * - any other conflicting prop is resolved by taking the value from the rightmost props object
12
+ * @param props One or more props objects to merge. Props further to the right take precedence.
13
+ */
14
+ export declare function mergeProps<T extends object[]>(...props: T): {
15
+ [K in keyof UnionToIntersection<T[number]>]: K extends 'className' ? string : K extends 'style' ? UnionToIntersection<T[number]>[K] : K extends 'ref' ? RefCallback<any> : Exclude<Extract<T[number], {
16
+ [Q in K]: unknown;
17
+ }>[K], undefined>;
18
+ };
19
+ export {};
@@ -0,0 +1,104 @@
1
+ import cn from 'classnames';
2
+ /**
3
+ * Assigns a value to a single ref — handles callback refs, object refs, null, and undefined.
4
+ * Returns the cleanup function if the callback ref returned one.
5
+ */
6
+
7
+ function assignRef(ref, value) {
8
+ if (ref == null) {
9
+ return;
10
+ }
11
+
12
+ if (typeof ref === 'function') {
13
+ return ref(value);
14
+ }
15
+
16
+ ref.current = value;
17
+ }
18
+ /**
19
+ * Merges multiple refs into a single callback ref.
20
+ * All provided refs are assigned in left-to-right order.
21
+ * Cleanup functions returned by callback refs are called on detach.
22
+ */
23
+
24
+
25
+ function mergeRefs() {
26
+ for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) {
27
+ refs[_key] = arguments[_key];
28
+ }
29
+
30
+ return value => {
31
+ const cleanups = refs.map(ref => assignRef(ref, value)); // return a combined cleanup only if at least one callback ref provided one.
32
+ // when React uses the cleanup API it will NOT call our merged ref with null on unmount,
33
+ // so we must manually null-out every ref that had no cleanup of its own.
34
+
35
+ if (cleanups.some(Boolean)) {
36
+ return () => cleanups.forEach((cleanup, i) => {
37
+ if (typeof cleanup === 'function') {
38
+ cleanup();
39
+ } else {
40
+ // simulate the ref(null) call that React skips when a cleanup is returned
41
+ assignRef(refs[i], null);
42
+ }
43
+ });
44
+ }
45
+ };
46
+ }
47
+
48
+ function pushProp(target, key, value) {
49
+ if (key === 'ref') {
50
+ target.ref = target.ref ? mergeRefs(target.ref, value) : value;
51
+ } else if (key === 'className') {
52
+ target.className = cn(target.className, value);
53
+ } else if (key === 'style') {
54
+ target.style = { ...target.style,
55
+ ...value
56
+ };
57
+ } else if (typeof value === 'function') {
58
+ const oldFn = target[key];
59
+ target[key] = oldFn ? function () {
60
+ oldFn(...arguments);
61
+ value(...arguments);
62
+ } : value;
63
+ } else if (!(key in target) || value !== undefined) {
64
+ // for any other duplicate prop, the value from the later object takes precedence;
65
+ // undefined is ignored on duplicated so it cannot erase an existing value
66
+ target[key] = value;
67
+ }
68
+ }
69
+ /**
70
+ * Combines multiple sets of props into a single object:
71
+ * - conflicting `className` values are joined with a space
72
+ * - conflicting `style` objects are shallow-merged (rightmost wins on conflict)
73
+ * - conflicting function props (event handlers) are composed and called left to right
74
+ * - conflicting `ref` props (object refs, callback refs, or null) are merged into a single
75
+ * callback ref that assigns all of them; cleanup functions returned by callback refs are
76
+ * collected and called together on detach
77
+ * - any other conflicting prop is resolved by taking the value from the rightmost props object
78
+ * @param props One or more props objects to merge. Props further to the right take precedence.
79
+ */
80
+
81
+
82
+ function mergeProps() {
83
+ for (var _len2 = arguments.length, props = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
84
+ props[_key2] = arguments[_key2];
85
+ }
86
+
87
+ if (props.length === 1) {
88
+ return props[0];
89
+ }
90
+
91
+ return props.reduce((merged, ps) => {
92
+ for (const key in ps) {
93
+ if (!ps.hasOwnProperty(key)) {
94
+ continue;
95
+ }
96
+
97
+ pushProp(merged, key, ps[key]);
98
+ }
99
+
100
+ return merged;
101
+ }, {});
102
+ }
103
+
104
+ export { mergeProps };
@@ -0,0 +1 @@
1
+ export declare function throttle<A extends unknown[], R>(func: (...args: A) => R, wait: number): (...args: A) => R;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rescui/select",
3
- "version": "0.15.2",
3
+ "version": "0.16.0",
4
4
  "description": "",
5
5
  "license": "Apache-2.0",
6
6
  "author": "JetBrains",
@@ -16,13 +16,13 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@babel/runtime-corejs3": "^7.26.0",
19
- "@rescui/dropdown": "^0.9.6",
19
+ "@rescui/dropdown": "^0.9.7",
20
20
  "@rescui/form-field": "^0.1.2",
21
- "@rescui/menu": "^0.13.4",
22
- "@rescui/tag": "^0.13.6",
21
+ "@rescui/tag": "^0.13.7",
23
22
  "@rescui/use-resize-observer": "^0.3.0",
24
23
  "classnames": "^2.2.6",
25
- "scroll-into-view-if-needed": "2.2.20"
24
+ "downshift": "^9.3.2",
25
+ "scroll-into-view-if-needed": "3.1.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@rescui/ui-contexts": "^0.6.0",
@@ -41,5 +41,5 @@
41
41
  "build-pcss-api": "rescui-scripts build-pcss-api --file public-api.p.css"
42
42
  },
43
43
  "nx": {},
44
- "gitHead": "faa7a838502974c16bdf773ab001002d1b8dcca8"
44
+ "gitHead": "fcf55336342c842c02c07a178e9bacb9a033ef83"
45
45
  }
@@ -1,7 +0,0 @@
1
- export declare const ARROW_UP = "ArrowUp";
2
- export declare const ARROW_DOWN = "ArrowDown";
3
- export declare const SPACE = " ";
4
- export declare const ESCAPE = "Escape";
5
- export declare const ENTER = "Enter";
6
- export declare const TAB = "Tab";
7
- export declare const BACKSPACE = "Backspace";
package/lib/key-codes.js DELETED
@@ -1,8 +0,0 @@
1
- const ARROW_UP = 'ArrowUp';
2
- const ARROW_DOWN = 'ArrowDown';
3
- const SPACE = ' ';
4
- const ESCAPE = 'Escape';
5
- const ENTER = 'Enter';
6
- const TAB = 'Tab';
7
- const BACKSPACE = 'Backspace';
8
- export { ARROW_DOWN, ARROW_UP, BACKSPACE, ENTER, ESCAPE, SPACE, TAB };
@@ -1,15 +0,0 @@
1
- var styles = {
2
- "sizeS": "_sizeS_1kt3z5d_3",
3
- "sizeM": "_sizeM_1kt3z5d_6",
4
- "sizeL": "_sizeL_1kt3z5d_9",
5
- "menu": "_menu_1kt3z5d_13",
6
- "menuSizeS": "_menuSizeS_1kt3z5d_26",
7
- "menuSizeM": "_menuSizeM_1kt3z5d_30",
8
- "menuSizeL": "_menuSizeL_1kt3z5d_34",
9
- "withGroupsLabel": "_withGroupsLabel_1kt3z5d_40",
10
- "lastOption": "_lastOption_1kt3z5d_39",
11
- "divider": "_divider_1kt3z5d_45",
12
- "checkIcon": "_checkIcon_1kt3z5d_51",
13
- "observable": "_observable_1kt3z5d_56"
14
- };
15
- export { styles as default };
@@ -1,15 +0,0 @@
1
- var styles = {
2
- "themeLight": "_themeLight_1bgbtrf_6",
3
- "themeDark": "_themeDark_1bgbtrf_9",
4
- "sizeS": "_sizeS_1bgbtrf_13",
5
- "sizeM": "_sizeM_1bgbtrf_16",
6
- "sizeL": "_sizeL_1bgbtrf_19",
7
- "main": "_main_1bgbtrf_23",
8
- "label": "_label_1bgbtrf_27",
9
- "disabled": "_disabled_1bgbtrf_33",
10
- "footer": "_footer_1bgbtrf_38",
11
- "errorMessage": "_errorMessage_1bgbtrf_45",
12
- "error": "_error_1bgbtrf_45",
13
- "note": "_note_1bgbtrf_54"
14
- };
15
- export { styles as default };
@@ -1,86 +0,0 @@
1
- import React from 'react';
2
- import { Theme } from '@rescui/ui-contexts';
3
- import { SelectOptionOrGroup, SelectOption, SelectSize, SelectMode, NoOptionsMessage } from '../types';
4
- export interface MultiselectProps {
5
- /**
6
- * Additional class name
7
- */
8
- className?: string;
9
- id?: string;
10
- /**
11
- * Array of options
12
- */
13
- options: SelectOptionOrGroup[];
14
- /**
15
- * Is Multiselect preserve single string
16
- */
17
- isSingleLine?: boolean;
18
- /**
19
- * Is Multiselect supports clear the value
20
- */
21
- isClearable?: boolean;
22
- /**
23
- * Is Multiselect has been disabled
24
- */
25
- isDisabled?: boolean;
26
- /**
27
- * Is loader displayed inside select
28
- */
29
- isLoading?: boolean;
30
- /**
31
- * A hint to the user of what can be entered in the control
32
- */
33
- placeholder?: string;
34
- /**
35
- * Size
36
- */
37
- size?: SelectSize;
38
- /**
39
- * Appearance mode
40
- */
41
- mode?: SelectMode;
42
- /**
43
- * Appearance theme
44
- */
45
- theme?: Theme;
46
- /**
47
- * Value of the select
48
- */
49
- value: SelectOption[];
50
- /**
51
- * Change value callback. `value => ...`
52
- */
53
- onChange?: (newValue: SelectOption[]) => void;
54
- /**
55
- * Error state flag or React.ReactNode (use with forms)
56
- */
57
- error?: boolean | React.ReactNode;
58
- /**
59
- * If `true`, there will be reserved a space for a 1-line error message. Subsequent lines will be placed below normally.
60
- * If `false`, there will be no reservation.
61
- */
62
- reserveErrorLine?: boolean;
63
- /**
64
- * Label element upper then Multiselect element (use with forms)
65
- */
66
- label?: React.ReactNode;
67
- /**
68
- * Placement of dropdown element
69
- */
70
- placement?: 'auto-start' | 'auto' | 'auto-end' | 'top-start' | 'top' | 'top-end' | 'right-start' | 'right' | 'right-end' | 'bottom-end' | 'bottom' | 'bottom-start' | 'left-end' | 'left' | 'left-start';
71
- /**
72
- * Note element below then Multiselect element (use with forms)
73
- */
74
- note?: React.ReactNode;
75
- /**
76
- * Text to display when there are no options
77
- */
78
- noOptionsMessage?: NoOptionsMessage;
79
- /**
80
- * Input name attribute
81
- */
82
- name?: string;
83
- boldLabel?: boolean;
84
- }
85
- declare const Multiselect: React.FC<MultiselectProps>;
86
- export default Multiselect;