@rescui/select 0.15.1-RUI-280-Update-select-component-downshift-2f40ef205.67 → 0.15.2
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/lib/_virtual/index.css.js +12 -12
- package/lib/common-prop-types.d.ts +14 -9
- package/lib/common-prop-types.js +3 -4
- package/lib/index.css +432 -808
- package/lib/index.d.ts +6 -4
- package/lib/index.js +3 -3
- package/lib/key-codes.d.ts +7 -0
- package/lib/key-codes.js +8 -0
- package/lib/parts/common-select.p.module.css.js +15 -0
- package/lib/parts/foldable.js +2 -1
- package/lib/parts/form-trigger-wrapper.d.ts +7 -7
- package/lib/parts/form-trigger-wrapper.js +34 -16
- package/lib/parts/form-trigger.p.module.css.js +15 -0
- package/lib/parts/multiselect.d.ts +86 -0
- package/lib/parts/multiselect.js +455 -0
- package/lib/parts/native-select.d.ts +36 -0
- package/lib/parts/native-select.js +255 -0
- package/lib/parts/native-select.p.module.css.js +9 -0
- package/lib/parts/throttle.d.ts +1 -0
- package/lib/parts/trigger.d.ts +37 -0
- package/lib/parts/trigger.js +255 -0
- package/lib/parts/trigger.p.module.css.js +31 -0
- package/lib/parts/use-observable-force-rerender.d.ts +2 -0
- package/lib/parts/use-observable-force-rerender.js +16 -0
- package/lib/public-api.p.css +309 -545
- package/lib/public-api.pcss +309 -545
- package/lib/select.d.ts +91 -27
- package/lib/select.js +351 -51
- package/lib/types.d.ts +4 -167
- package/lib/utils.d.ts +22 -0
- package/lib/utils.js +199 -0
- package/package.json +12 -12
- package/lib/constants.d.ts +0 -6
- package/lib/constants.js +0 -7
- package/lib/hooks/use-a11y.d.ts +0 -29
- package/lib/hooks/use-a11y.js +0 -53
- package/lib/hooks/use-focus.d.ts +0 -10
- package/lib/hooks/use-focus.js +0 -17
- package/lib/hooks/use-hover.d.ts +0 -10
- package/lib/hooks/use-hover.js +0 -17
- package/lib/hooks/use-label-focus.d.ts +0 -9
- package/lib/hooks/use-label-focus.js +0 -22
- package/lib/hooks/use-multi-handlers.d.ts +0 -11
- package/lib/hooks/use-multi-handlers.js +0 -48
- package/lib/hooks/use-options.d.ts +0 -13
- package/lib/hooks/use-options.js +0 -89
- package/lib/multiselect.d.ts +0 -3
- package/lib/multiselect.js +0 -312
- package/lib/native-select.d.ts +0 -4
- package/lib/native-select.js +0 -211
- package/lib/parts/hidden-select.d.ts +0 -13
- package/lib/parts/hidden-select.js +0 -45
- package/lib/parts/icons.d.ts +0 -17
- package/lib/parts/icons.js +0 -69
- package/lib/parts/list-box.d.ts +0 -11
- package/lib/parts/list-box.js +0 -116
- package/lib/parts/multi-trigger.d.ts +0 -12
- package/lib/parts/multi-trigger.js +0 -74
- package/lib/parts/native-select-options-with-groups.d.ts +0 -8
- package/lib/parts/native-select-options-with-groups.js +0 -76
- package/lib/select-basic.d.ts +0 -3
- package/lib/select-basic.js +0 -203
- package/lib/select-searchable.d.ts +0 -3
- package/lib/select-searchable.js +0 -250
- package/lib/styles/common.p.module.css.js +0 -31
- package/lib/styles/form-trigger.p.module.css.js +0 -15
- package/lib/styles/list-box.p.module.css.js +0 -14
- package/lib/utils/calculate-max-height-by-items.d.ts +0 -13
- package/lib/utils/calculate-max-height-by-items.js +0 -22
- package/lib/utils/get-empty-message.d.ts +0 -6
- package/lib/utils/get-empty-message.js +0 -32
- package/lib/utils/get-option-value.d.ts +0 -2
- package/lib/utils/get-option-value.js +0 -11
- package/lib/utils/get-real-items-cnt.d.ts +0 -2
- package/lib/utils/get-real-items-cnt.js +0 -19
- package/lib/utils/get-text-from-nodes.d.ts +0 -2
- package/lib/utils/get-text-from-nodes.js +0 -28
- package/lib/utils/is-option-a-group.d.ts +0 -2
- package/lib/utils/is-option-a-group.js +0 -5
- package/lib/utils/item-to-string.d.ts +0 -2
- package/lib/utils/item-to-string.js +0 -7
- package/lib/utils/merge-props.d.ts +0 -29
- package/lib/utils/merge-props.js +0 -106
- package/lib/utils/throttle.d.ts +0 -1
- /package/lib/{utils → parts}/throttle.js +0 -0
- /package/lib/{hooks → parts}/use-backward-compatible-id.d.ts +0 -0
- /package/lib/{hooks → parts}/use-backward-compatible-id.js +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { useRef, useMemo, useCallback } from 'react';
|
|
2
|
-
import { getOptionValue } from '../utils/get-option-value.js';
|
|
3
|
-
|
|
4
|
-
const useMultiHandlers = _ref => {
|
|
5
|
-
let {
|
|
6
|
-
selectedItems,
|
|
7
|
-
onChange
|
|
8
|
-
} = _ref;
|
|
9
|
-
const onChangeRef = useRef(null);
|
|
10
|
-
onChangeRef.current = onChange;
|
|
11
|
-
const selectedMap = useMemo(() => new Map(selectedItems.map(item => [getOptionValue(item), item])), [selectedItems]);
|
|
12
|
-
const addItem = useCallback(item => {
|
|
13
|
-
var _onChangeRef$current;
|
|
14
|
-
|
|
15
|
-
if (selectedMap.has(getOptionValue(item))) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
(_onChangeRef$current = onChangeRef.current) === null || _onChangeRef$current === void 0 || _onChangeRef$current.call(onChangeRef, [...selectedMap.values(), item]);
|
|
20
|
-
}, [selectedMap]);
|
|
21
|
-
const removeItem = useCallback(item => {
|
|
22
|
-
var _onChangeRef$current2;
|
|
23
|
-
|
|
24
|
-
const key = getOptionValue(item);
|
|
25
|
-
(_onChangeRef$current2 = onChangeRef.current) === null || _onChangeRef$current2 === void 0 || _onChangeRef$current2.call(onChangeRef, [...selectedMap.entries()].filter(_ref2 => {
|
|
26
|
-
let [k] = _ref2;
|
|
27
|
-
return k !== key;
|
|
28
|
-
}).map(_ref3 => {
|
|
29
|
-
let [, v] = _ref3;
|
|
30
|
-
return v;
|
|
31
|
-
}));
|
|
32
|
-
}, [selectedMap]);
|
|
33
|
-
|
|
34
|
-
const removeAllItems = () => {
|
|
35
|
-
var _onChangeRef$current3;
|
|
36
|
-
|
|
37
|
-
(_onChangeRef$current3 = onChangeRef.current) === null || _onChangeRef$current3 === void 0 || _onChangeRef$current3.call(onChangeRef, []);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
selectedMap,
|
|
42
|
-
addItem,
|
|
43
|
-
removeItem,
|
|
44
|
-
removeAllItems
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export { useMultiHandlers };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { SelectOptionOrGroup, SelectOption, ListBoxItem } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
* Convert an array of options with possible groups to the flat array of options, stripping them of the groups.
|
|
5
|
-
* Also creating a list for ListBox component with indexes and keys.
|
|
6
|
-
* Supports filtering by returning the setFilterString function.
|
|
7
|
-
* @param options
|
|
8
|
-
*/
|
|
9
|
-
export declare const useOptions: (options: SelectOptionOrGroup[]) => {
|
|
10
|
-
setFilterString: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
11
|
-
flattenedOptions: SelectOption[];
|
|
12
|
-
listBoxItems: ListBoxItem[];
|
|
13
|
-
};
|
package/lib/hooks/use-options.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
|
|
2
|
-
import { useState, useMemo } from 'react';
|
|
3
|
-
import { isOptionAGroup } from '../utils/is-option-a-group.js';
|
|
4
|
-
import { getTextFromNodes } from '../utils/get-text-from-nodes.js';
|
|
5
|
-
import { getOptionValue } from '../utils/get-option-value.js';
|
|
6
|
-
|
|
7
|
-
const createFilter = substring => {
|
|
8
|
-
if (substring.length === 0) {
|
|
9
|
-
return () => true;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const lowerSubstring = substring.toLowerCase();
|
|
13
|
-
return string => {
|
|
14
|
-
var _context;
|
|
15
|
-
|
|
16
|
-
return _includesInstanceProperty(_context = string.toLowerCase()).call(_context, lowerSubstring);
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Convert an array of options with possible groups to the flat array of options, stripping them of the groups.
|
|
21
|
-
* Also creating a list for ListBox component with indexes and keys.
|
|
22
|
-
* Supports filtering by returning the setFilterString function.
|
|
23
|
-
* @param options
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const useOptions = options => {
|
|
28
|
-
const [filterString, setFilterString] = useState('');
|
|
29
|
-
const filterFn = useMemo(() => createFilter(filterString), [filterString]);
|
|
30
|
-
const processedOptions = useMemo(() => {
|
|
31
|
-
const flattenedOptions = [];
|
|
32
|
-
const listBoxItems = [];
|
|
33
|
-
let index = 0;
|
|
34
|
-
|
|
35
|
-
const createOptionItem = option => {
|
|
36
|
-
return { ...option,
|
|
37
|
-
index: index++,
|
|
38
|
-
type: 'option',
|
|
39
|
-
key: getOptionValue(option)
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
options.forEach((optionOrGroup, arrayIndex) => {
|
|
44
|
-
if (isOptionAGroup(optionOrGroup)) {
|
|
45
|
-
const group = optionOrGroup;
|
|
46
|
-
|
|
47
|
-
if (!group.options || group.options.length === 0) {
|
|
48
|
-
return;
|
|
49
|
-
} // Render as Group (with or without label)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const groupLabelText = group.label ? getTextFromNodes(group.label) : ''; // Use a special prefix that's unlikely to collide with user values
|
|
53
|
-
|
|
54
|
-
const groupKey = `\0__rs_select_group_${arrayIndex}_${groupLabelText}`;
|
|
55
|
-
const listBoxGroupItem = { ...group,
|
|
56
|
-
type: 'group',
|
|
57
|
-
options: [],
|
|
58
|
-
key: groupKey
|
|
59
|
-
};
|
|
60
|
-
group.options.forEach(option => {
|
|
61
|
-
if (filterFn(getTextFromNodes(option.label))) {
|
|
62
|
-
flattenedOptions.push(option);
|
|
63
|
-
listBoxGroupItem.options.push(createOptionItem(option));
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
if (listBoxGroupItem.options.length > 0) {
|
|
68
|
-
listBoxItems.push(listBoxGroupItem);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (filterFn(getTextFromNodes(optionOrGroup.label))) {
|
|
75
|
-
flattenedOptions.push(optionOrGroup);
|
|
76
|
-
listBoxItems.push(createOptionItem(optionOrGroup));
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
return {
|
|
80
|
-
flattenedOptions,
|
|
81
|
-
listBoxItems
|
|
82
|
-
};
|
|
83
|
-
}, [options, filterFn]);
|
|
84
|
-
return { ...processedOptions,
|
|
85
|
-
setFilterString
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export { useOptions };
|
package/lib/multiselect.d.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { MultiselectProps } from './types';
|
|
3
|
-
export declare function Multiselect({ options, value: selectedItems, onChange, error, label, note, size, mode, theme: themeFromProps, placement, isSingleLine, boldLabel, reserveErrorLine, maxVisibleItems, isClearable, isLoading, isDisabled, name, noOptionsMessage, className, id, style, placeholder, ...rest }: MultiselectProps): JSX.Element;
|
package/lib/multiselect.js
DELETED
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import cn from 'classnames';
|
|
3
|
-
import { Dropdown } from '@rescui/dropdown';
|
|
4
|
-
import { useSelect } from 'downshift';
|
|
5
|
-
import { useThemeWithUndefined } from '@rescui/ui-contexts';
|
|
6
|
-
import scrollIntoView from 'scroll-into-view-if-needed';
|
|
7
|
-
import { useLabelFocus } from './hooks/use-label-focus.js';
|
|
8
|
-
import { useOptions } from './hooks/use-options.js';
|
|
9
|
-
import { useMultiHandlers } from './hooks/use-multi-handlers.js';
|
|
10
|
-
import { useA11y } from './hooks/use-a11y.js';
|
|
11
|
-
import { ListBox } from './parts/list-box.js';
|
|
12
|
-
import { Icons } from './parts/icons.js';
|
|
13
|
-
import { MultiTrigger } from './parts/multi-trigger.js';
|
|
14
|
-
import { HiddenSelect } from './parts/hidden-select.js';
|
|
15
|
-
import { FormTriggerWrapper } from './parts/form-trigger-wrapper.js';
|
|
16
|
-
import { getEmptyMessage } from './utils/get-empty-message.js';
|
|
17
|
-
import { mergeProps } from './utils/merge-props.js';
|
|
18
|
-
import { itemToString } from './utils/item-to-string.js';
|
|
19
|
-
import { getOptionValue } from './utils/get-option-value.js';
|
|
20
|
-
import { getRealItemsCnt } from './utils/get-real-items-cnt.js';
|
|
21
|
-
import styles from './styles/common.p.module.css.js';
|
|
22
|
-
const THEME_STYLES = {
|
|
23
|
-
light: styles.themeLight,
|
|
24
|
-
dark: styles.themeDark
|
|
25
|
-
};
|
|
26
|
-
const SIZE_STYLES = {
|
|
27
|
-
s: styles.sizeS,
|
|
28
|
-
m: styles.sizeM,
|
|
29
|
-
l: styles.sizeL
|
|
30
|
-
};
|
|
31
|
-
const MODE_STYLES = {
|
|
32
|
-
classic: styles.classic,
|
|
33
|
-
rock: styles.rock
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const stateReducer = (state, actionAndChanges) => {
|
|
37
|
-
const {
|
|
38
|
-
changes,
|
|
39
|
-
type
|
|
40
|
-
} = actionAndChanges; // console.log(type, state, changes);
|
|
41
|
-
|
|
42
|
-
switch (type) {
|
|
43
|
-
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
|
|
44
|
-
case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
|
|
45
|
-
case useSelect.stateChangeTypes.ItemClick:
|
|
46
|
-
return { ...changes,
|
|
47
|
-
isOpen: true,
|
|
48
|
-
highlightedIndex: state.highlightedIndex
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
default:
|
|
52
|
-
return { ...changes,
|
|
53
|
-
selectedItem: null
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}; // eslint-disable-next-line complexity
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
function Multiselect(_ref) {
|
|
60
|
-
let {
|
|
61
|
-
options = [],
|
|
62
|
-
value: selectedItems = [],
|
|
63
|
-
onChange,
|
|
64
|
-
error,
|
|
65
|
-
label,
|
|
66
|
-
note,
|
|
67
|
-
size = 'm',
|
|
68
|
-
mode = 'classic',
|
|
69
|
-
theme: themeFromProps,
|
|
70
|
-
placement = 'bottom',
|
|
71
|
-
isSingleLine = false,
|
|
72
|
-
boldLabel = true,
|
|
73
|
-
reserveErrorLine = false,
|
|
74
|
-
maxVisibleItems = 5,
|
|
75
|
-
isClearable = false,
|
|
76
|
-
isLoading = false,
|
|
77
|
-
isDisabled = false,
|
|
78
|
-
name,
|
|
79
|
-
noOptionsMessage,
|
|
80
|
-
className,
|
|
81
|
-
id,
|
|
82
|
-
style,
|
|
83
|
-
placeholder,
|
|
84
|
-
...rest
|
|
85
|
-
} = _ref;
|
|
86
|
-
const theme = useThemeWithUndefined(themeFromProps);
|
|
87
|
-
const triggerRef = React.useRef(null);
|
|
88
|
-
const menuRef = React.useRef(null);
|
|
89
|
-
const dropdownRef = React.useRef(null);
|
|
90
|
-
const {
|
|
91
|
-
selectedMap,
|
|
92
|
-
removeItem: removeSelectedItem,
|
|
93
|
-
addItem: addSelectedItem,
|
|
94
|
-
removeAllItems: reset
|
|
95
|
-
} = useMultiHandlers({
|
|
96
|
-
selectedItems,
|
|
97
|
-
onChange
|
|
98
|
-
});
|
|
99
|
-
const {
|
|
100
|
-
flattenedOptions,
|
|
101
|
-
listBoxItems
|
|
102
|
-
} = useOptions(options);
|
|
103
|
-
const isListBoxEmpty = getRealItemsCnt(listBoxItems) === 0;
|
|
104
|
-
const {
|
|
105
|
-
fieldProps,
|
|
106
|
-
errorMessageProps,
|
|
107
|
-
descriptionProps,
|
|
108
|
-
baseId
|
|
109
|
-
} = useA11y({
|
|
110
|
-
prefix: 'multiselect',
|
|
111
|
-
error,
|
|
112
|
-
description: note
|
|
113
|
-
});
|
|
114
|
-
const {
|
|
115
|
-
isOpen,
|
|
116
|
-
getToggleButtonProps,
|
|
117
|
-
getLabelProps,
|
|
118
|
-
getMenuProps,
|
|
119
|
-
highlightedIndex,
|
|
120
|
-
getItemProps,
|
|
121
|
-
setHighlightedIndex
|
|
122
|
-
} = useSelect({
|
|
123
|
-
items: flattenedOptions,
|
|
124
|
-
itemToString,
|
|
125
|
-
id: baseId,
|
|
126
|
-
|
|
127
|
-
onIsOpenChange(newIsOpen) {
|
|
128
|
-
if (newIsOpen) {
|
|
129
|
-
// set the first selected item as a highlighted item if the popup is opened
|
|
130
|
-
const firstSelectedKey = [...selectedMap.keys()][0];
|
|
131
|
-
|
|
132
|
-
if (firstSelectedKey) {
|
|
133
|
-
setHighlightedIndex(flattenedOptions.findIndex(item => firstSelectedKey === getOptionValue(item)));
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
stateReducer,
|
|
139
|
-
// there's no actual selection happening in the hook, we're doing it custom via controlled props.
|
|
140
|
-
selectedItem: null,
|
|
141
|
-
// defining our scroll behavior because on the first menu render the hook
|
|
142
|
-
// doesn't know menuRef and use page as the scroll boundary
|
|
143
|
-
scrollIntoView: (listItemEl, listEl) => {
|
|
144
|
-
scrollIntoView(listItemEl, {
|
|
145
|
-
scrollMode: 'if-needed',
|
|
146
|
-
block: 'nearest',
|
|
147
|
-
boundary: listEl ?? menuRef.current
|
|
148
|
-
});
|
|
149
|
-
},
|
|
150
|
-
onSelectedItemChange: _ref2 => {
|
|
151
|
-
let {
|
|
152
|
-
selectedItem
|
|
153
|
-
} = _ref2;
|
|
154
|
-
|
|
155
|
-
if (!selectedItem) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const changedValue = getOptionValue(selectedItem);
|
|
160
|
-
|
|
161
|
-
if (selectedMap.has(changedValue)) {
|
|
162
|
-
removeSelectedItem(selectedItem);
|
|
163
|
-
} else {
|
|
164
|
-
addSelectedItem(selectedItem);
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
|
|
168
|
-
isItemDisabled(item) {
|
|
169
|
-
return item && item.disabled;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
});
|
|
173
|
-
const menuProps = getMenuProps({
|
|
174
|
-
ref: menuRef,
|
|
175
|
-
'aria-multiselectable': isListBoxEmpty ? undefined : 'true'
|
|
176
|
-
}, {
|
|
177
|
-
suppressRefError: true
|
|
178
|
-
});
|
|
179
|
-
const triggerProps = getToggleButtonProps({
|
|
180
|
-
ref: triggerRef,
|
|
181
|
-
// eslint-disable-next-line complexity
|
|
182
|
-
onKeyDown: event => {
|
|
183
|
-
// shift + arrow up/down selection (when popup is open)
|
|
184
|
-
if (isOpen && event.shiftKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {
|
|
185
|
-
const newHighlightedIndex = event.key === 'ArrowUp' ? Math.max(highlightedIndex - 1, 0) : Math.min(highlightedIndex + 1, flattenedOptions.length - 1);
|
|
186
|
-
|
|
187
|
-
if (newHighlightedIndex === highlightedIndex) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
addSelectedItem(flattenedOptions[newHighlightedIndex]);
|
|
192
|
-
} // backspace removing the last selected item (when popup is closed)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (!isOpen && event.key === 'Backspace') {
|
|
196
|
-
removeSelectedItem(selectedItems[selectedItems.length - 1]);
|
|
197
|
-
} // delete removing all selected items (when popup is closed)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (!isOpen && event.key === 'Delete') {
|
|
201
|
-
reset();
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
// fix screen-reader focus on an opened popup with an empty list
|
|
205
|
-
...(isOpen && isListBoxEmpty ? {
|
|
206
|
-
'aria-activedescendant': menuProps.id
|
|
207
|
-
} : {})
|
|
208
|
-
}); // recalculate the popup position after a possible trigger height change
|
|
209
|
-
|
|
210
|
-
useEffect(() => {
|
|
211
|
-
if (dropdownRef.current) {
|
|
212
|
-
dropdownRef.current.scheduleUpdate();
|
|
213
|
-
}
|
|
214
|
-
}, [selectedItems]);
|
|
215
|
-
const {
|
|
216
|
-
isFocusedByLabel,
|
|
217
|
-
labelClickProps,
|
|
218
|
-
triggerFocusProps: labelFocusForTriggerProps
|
|
219
|
-
} = useLabelFocus();
|
|
220
|
-
const emptyListMessage = getEmptyMessage({
|
|
221
|
-
isLoading,
|
|
222
|
-
isNothingFound: false,
|
|
223
|
-
noOptionsMessage
|
|
224
|
-
});
|
|
225
|
-
const listBoxState = {
|
|
226
|
-
selectedMap,
|
|
227
|
-
selectionMode: 'multiple',
|
|
228
|
-
highlightedIndex,
|
|
229
|
-
getItemProps,
|
|
230
|
-
menuProps
|
|
231
|
-
};
|
|
232
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
233
|
-
className: cn(className, styles.root, THEME_STYLES[theme], SIZE_STYLES[size], MODE_STYLES[mode], isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
|
|
234
|
-
id: id,
|
|
235
|
-
style: style,
|
|
236
|
-
"data-test": "multiselect"
|
|
237
|
-
}, /*#__PURE__*/React.createElement(FormTriggerWrapper, {
|
|
238
|
-
theme: theme,
|
|
239
|
-
size: size,
|
|
240
|
-
disabled: isDisabled,
|
|
241
|
-
label: label,
|
|
242
|
-
labelProps: mergeProps(getLabelProps(), labelClickProps),
|
|
243
|
-
boldLabel: boldLabel,
|
|
244
|
-
error: error,
|
|
245
|
-
reserveErrorLine: reserveErrorLine,
|
|
246
|
-
errorMessageProps: errorMessageProps,
|
|
247
|
-
note: note,
|
|
248
|
-
descriptionProps: descriptionProps
|
|
249
|
-
}, /*#__PURE__*/React.createElement(HiddenSelect, {
|
|
250
|
-
name: name,
|
|
251
|
-
value: selectedItems,
|
|
252
|
-
isMultiple: true,
|
|
253
|
-
options: flattenedOptions
|
|
254
|
-
}), /*#__PURE__*/React.createElement(Dropdown, {
|
|
255
|
-
mode: mode,
|
|
256
|
-
theme: theme,
|
|
257
|
-
ref: dropdownRef,
|
|
258
|
-
placement: placement,
|
|
259
|
-
maxWidth: "trigger",
|
|
260
|
-
minWidth: "trigger",
|
|
261
|
-
isOpen: isOpen,
|
|
262
|
-
cancelCloseAnimation: true,
|
|
263
|
-
disableFocusLock: true,
|
|
264
|
-
trigger: _ref3 => {
|
|
265
|
-
let {
|
|
266
|
-
ref: triggerRefForDropdown
|
|
267
|
-
} = _ref3;
|
|
268
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
269
|
-
className: styles.triggerContainer,
|
|
270
|
-
"data-open": isOpen,
|
|
271
|
-
"data-label-focused": isFocusedByLabel
|
|
272
|
-
}, /*#__PURE__*/React.createElement("div", { ...rest,
|
|
273
|
-
...mergeProps(fieldProps, // aria-invalid & aria-describedby, rest are overridden by triggerProps
|
|
274
|
-
triggerProps, labelFocusForTriggerProps, {
|
|
275
|
-
ref: triggerRefForDropdown
|
|
276
|
-
}),
|
|
277
|
-
className: cn(styles.trigger, !isSingleLine && styles.canBeMultiline),
|
|
278
|
-
"data-open": isOpen,
|
|
279
|
-
"data-label-focused": isFocusedByLabel,
|
|
280
|
-
"data-test": "multiselect__trigger"
|
|
281
|
-
}, /*#__PURE__*/React.createElement(MultiTrigger, {
|
|
282
|
-
selectedItems: selectedItems,
|
|
283
|
-
valueProps: {},
|
|
284
|
-
isSingleLine: isSingleLine,
|
|
285
|
-
isDisabled: isDisabled,
|
|
286
|
-
placeholder: placeholder,
|
|
287
|
-
triggerRef: triggerRef,
|
|
288
|
-
removeSelectedItem: removeSelectedItem
|
|
289
|
-
}), /*#__PURE__*/React.createElement(Icons, {
|
|
290
|
-
isLoading: isLoading,
|
|
291
|
-
canHaveClearIcon: isClearable && !isDisabled && selectedItems.length > 0,
|
|
292
|
-
onClear: () => {
|
|
293
|
-
var _triggerRef$current;
|
|
294
|
-
|
|
295
|
-
reset();
|
|
296
|
-
(_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
|
|
297
|
-
focusVisible: false
|
|
298
|
-
});
|
|
299
|
-
},
|
|
300
|
-
triggerId: triggerProps.id
|
|
301
|
-
})));
|
|
302
|
-
}
|
|
303
|
-
}, /*#__PURE__*/React.createElement(ListBox, {
|
|
304
|
-
state: listBoxState,
|
|
305
|
-
size: size,
|
|
306
|
-
maxVisibleItems: maxVisibleItems,
|
|
307
|
-
emptyListMessage: emptyListMessage,
|
|
308
|
-
items: listBoxItems
|
|
309
|
-
}))));
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
export { Multiselect };
|
package/lib/native-select.d.ts
DELETED
package/lib/native-select.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import cn from 'classnames';
|
|
5
|
-
import { useThemeWithUndefined } from '@rescui/ui-contexts';
|
|
6
|
-
import { ErrorMessage } from '@rescui/form-field';
|
|
7
|
-
import { nativeOptionType, nativeOptionsGroupType, noOptionsMessageType } from './common-prop-types.js';
|
|
8
|
-
import { useA11y } from './hooks/use-a11y.js';
|
|
9
|
-
import { useHover } from './hooks/use-hover.js';
|
|
10
|
-
import { useFocus } from './hooks/use-focus.js';
|
|
11
|
-
import { FormTriggerWrapper } from './parts/form-trigger-wrapper.js';
|
|
12
|
-
import { NativeSelectOptionsWithGroups } from './parts/native-select-options-with-groups.js';
|
|
13
|
-
import { Icons } from './parts/icons.js';
|
|
14
|
-
import { isOptionAGroup } from './utils/is-option-a-group.js';
|
|
15
|
-
import { getEmptyMessage } from './utils/get-empty-message.js';
|
|
16
|
-
import { mergeProps } from './utils/merge-props.js';
|
|
17
|
-
import styles from './styles/common.p.module.css.js';
|
|
18
|
-
|
|
19
|
-
function findSelectedOption(options, selectedValue) {
|
|
20
|
-
let result = null;
|
|
21
|
-
|
|
22
|
-
const checkOption = option => {
|
|
23
|
-
if (result === null || option.value === selectedValue) {
|
|
24
|
-
result = option;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
options.forEach(optionOrGroup => {
|
|
29
|
-
if (isOptionAGroup(optionOrGroup)) {
|
|
30
|
-
var _group$options;
|
|
31
|
-
|
|
32
|
-
const group = optionOrGroup;
|
|
33
|
-
(_group$options = group.options) === null || _group$options === void 0 || _group$options.forEach(checkOption);
|
|
34
|
-
} else {
|
|
35
|
-
checkOption(optionOrGroup);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const SIZE_STYLES = {
|
|
42
|
-
s: styles.sizeS,
|
|
43
|
-
m: styles.sizeM,
|
|
44
|
-
l: styles.sizeL
|
|
45
|
-
};
|
|
46
|
-
const THEME_STYLES = {
|
|
47
|
-
light: styles.themeLight,
|
|
48
|
-
dark: styles.themeDark
|
|
49
|
-
}; // eslint-disable-next-line complexity
|
|
50
|
-
|
|
51
|
-
const NativeSelect = _ref => {
|
|
52
|
-
let {
|
|
53
|
-
options = [],
|
|
54
|
-
size = 'm',
|
|
55
|
-
theme: themeFromProps,
|
|
56
|
-
className = null,
|
|
57
|
-
id,
|
|
58
|
-
style,
|
|
59
|
-
value,
|
|
60
|
-
onChange,
|
|
61
|
-
placeholder,
|
|
62
|
-
isLoading = false,
|
|
63
|
-
isDisabled = false,
|
|
64
|
-
isClearable = false,
|
|
65
|
-
trigger,
|
|
66
|
-
label,
|
|
67
|
-
note,
|
|
68
|
-
error,
|
|
69
|
-
reserveErrorLine = false,
|
|
70
|
-
noOptionsMessage,
|
|
71
|
-
name,
|
|
72
|
-
boldLabel = true,
|
|
73
|
-
...rest
|
|
74
|
-
} = _ref;
|
|
75
|
-
const triggerRef = React.useRef(null);
|
|
76
|
-
const {
|
|
77
|
-
labelProps,
|
|
78
|
-
fieldProps,
|
|
79
|
-
errorMessageProps,
|
|
80
|
-
descriptionProps
|
|
81
|
-
} = useA11y({
|
|
82
|
-
prefix: 'native-select',
|
|
83
|
-
error,
|
|
84
|
-
description: note,
|
|
85
|
-
label,
|
|
86
|
-
fieldRef: triggerRef
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const reset = () => onChange(null);
|
|
90
|
-
|
|
91
|
-
const theme = useThemeWithUndefined(themeFromProps);
|
|
92
|
-
|
|
93
|
-
const handleChange = event => {
|
|
94
|
-
const newValue = event.target.value;
|
|
95
|
-
const selectedOption = findSelectedOption(options, newValue);
|
|
96
|
-
|
|
97
|
-
if (onChange) {
|
|
98
|
-
onChange(selectedOption);
|
|
99
|
-
}
|
|
100
|
-
}; // delete it when triggerFunc is migrated to the css-states instead of js-props for hover/focus
|
|
101
|
-
// replace it with ":focus + &" selector in that case
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const {
|
|
105
|
-
isFocused,
|
|
106
|
-
focusProps
|
|
107
|
-
} = useFocus({
|
|
108
|
-
isDisabled
|
|
109
|
-
}); // same as above, could be replaced with ":hover + &" selector
|
|
110
|
-
|
|
111
|
-
const {
|
|
112
|
-
isHovered,
|
|
113
|
-
hoverProps
|
|
114
|
-
} = useHover({
|
|
115
|
-
isDisabled
|
|
116
|
-
});
|
|
117
|
-
const emptyListMessage = getEmptyMessage({
|
|
118
|
-
isLoading,
|
|
119
|
-
isNothingFound: false,
|
|
120
|
-
noOptionsMessage
|
|
121
|
-
});
|
|
122
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
123
|
-
className: cn(className, styles.root, SIZE_STYLES[size], THEME_STYLES[theme], styles.classic, isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
|
|
124
|
-
id: id,
|
|
125
|
-
style: style,
|
|
126
|
-
"data-test": "native-select"
|
|
127
|
-
}, /*#__PURE__*/React.createElement(FormTriggerWrapper, {
|
|
128
|
-
theme: theme,
|
|
129
|
-
size: size,
|
|
130
|
-
disabled: isDisabled,
|
|
131
|
-
label: label,
|
|
132
|
-
labelProps: mergeProps(labelProps),
|
|
133
|
-
boldLabel: boldLabel,
|
|
134
|
-
error: error,
|
|
135
|
-
errorMessageProps: errorMessageProps,
|
|
136
|
-
reserveErrorLine: reserveErrorLine,
|
|
137
|
-
note: note,
|
|
138
|
-
descriptionProps: descriptionProps
|
|
139
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
140
|
-
className: styles.triggerContainer
|
|
141
|
-
}, /*#__PURE__*/React.createElement("select", { ...rest,
|
|
142
|
-
...mergeProps(fieldProps, focusProps, hoverProps, {
|
|
143
|
-
onKeyDown: event => {
|
|
144
|
-
// backspace and backspace removing the last selected item (when popup is closed)
|
|
145
|
-
if (isClearable && (event.key === 'Backspace' || event.key === 'Delete')) {
|
|
146
|
-
reset();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}),
|
|
150
|
-
ref: triggerRef,
|
|
151
|
-
"data-test": "native-select_select",
|
|
152
|
-
"data-rs-internal": 'select-native__select',
|
|
153
|
-
className: styles.select,
|
|
154
|
-
disabled: isDisabled ? true : undefined,
|
|
155
|
-
onChange: handleChange,
|
|
156
|
-
name: name,
|
|
157
|
-
value: (value === null || value === void 0 ? void 0 : value.value) ?? ''
|
|
158
|
-
}, /*#__PURE__*/React.createElement(NativeSelectOptionsWithGroups, {
|
|
159
|
-
optionsWithGroups: options,
|
|
160
|
-
placeholder: placeholder,
|
|
161
|
-
emptyListMessage: emptyListMessage
|
|
162
|
-
})), trigger ? trigger({
|
|
163
|
-
focused: isFocused,
|
|
164
|
-
hovered: isHovered,
|
|
165
|
-
selectedLabel: value === null || value === void 0 ? void 0 : value.label,
|
|
166
|
-
selectedValue: value === null || value === void 0 ? void 0 : value.value,
|
|
167
|
-
placeholder
|
|
168
|
-
}) : /*#__PURE__*/React.createElement("div", {
|
|
169
|
-
className: cn(styles.trigger),
|
|
170
|
-
"data-test": 'native-select_trigger',
|
|
171
|
-
"data-rs-internal": 'select-native-trigger'
|
|
172
|
-
}, /*#__PURE__*/React.createElement("span", {
|
|
173
|
-
className: cn(styles.triggerText, !(value !== null && value !== void 0 && value.value) && styles.labelNotSelected),
|
|
174
|
-
"data-test": 'native-select_trigger_text',
|
|
175
|
-
"aria-hidden": "true"
|
|
176
|
-
}, (value === null || value === void 0 ? void 0 : value.label) ?? placeholder), /*#__PURE__*/React.createElement(Icons, {
|
|
177
|
-
isLoading: isLoading,
|
|
178
|
-
triggerId: fieldProps.id,
|
|
179
|
-
onClear: () => {
|
|
180
|
-
var _triggerRef$current;
|
|
181
|
-
|
|
182
|
-
reset();
|
|
183
|
-
(_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
|
|
184
|
-
focusVisible: false
|
|
185
|
-
});
|
|
186
|
-
},
|
|
187
|
-
canHaveClearIcon: isClearable && !isDisabled && Boolean(value === null || value === void 0 ? void 0 : value.value)
|
|
188
|
-
})))));
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
NativeSelect.propTypes = {
|
|
192
|
-
className: PropTypes.string,
|
|
193
|
-
style: PropTypes.object,
|
|
194
|
-
id: PropTypes.string,
|
|
195
|
-
options: PropTypes.arrayOf(PropTypes.oneOfType([nativeOptionType, nativeOptionsGroupType])),
|
|
196
|
-
value: nativeOptionType,
|
|
197
|
-
onChange: PropTypes.func,
|
|
198
|
-
size: PropTypes.oneOf(['m', 's', 'l']),
|
|
199
|
-
theme: PropTypes.oneOf(['light', 'dark']),
|
|
200
|
-
placeholder: PropTypes.string,
|
|
201
|
-
isDisabled: PropTypes.bool,
|
|
202
|
-
isLoading: PropTypes.bool,
|
|
203
|
-
trigger: PropTypes.func,
|
|
204
|
-
error: ErrorMessage.propTypes.children,
|
|
205
|
-
label: PropTypes.node,
|
|
206
|
-
note: PropTypes.node,
|
|
207
|
-
noOptionsMessage: noOptionsMessageType,
|
|
208
|
-
name: PropTypes.string,
|
|
209
|
-
boldLabel: PropTypes.bool
|
|
210
|
-
};
|
|
211
|
-
export { NativeSelect, NativeSelect as default };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { SelectOption } from '../types';
|
|
3
|
-
export declare type HiddenSelectProps = {
|
|
4
|
-
name?: string;
|
|
5
|
-
options: SelectOption[];
|
|
6
|
-
} & ({
|
|
7
|
-
value: SelectOption[];
|
|
8
|
-
isMultiple: true;
|
|
9
|
-
} | {
|
|
10
|
-
value: SelectOption;
|
|
11
|
-
isMultiple: false;
|
|
12
|
-
});
|
|
13
|
-
export declare const HiddenSelect: ({ name, options, value, isMultiple }: HiddenSelectProps) => JSX.Element;
|