@rescui/select 0.14.4-RUI-286-Fix-tooltip-stacking-f4145b01.1 → 0.15.1-RUI-280-Update-select-component-026338d06.52
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 +9 -14
- package/lib/common-prop-types.js +4 -3
- package/lib/constants.d.ts +7 -0
- package/lib/constants.js +8 -0
- package/lib/hooks/use-css-context-transfer.d.ts +14 -0
- package/lib/hooks/use-css-context-transfer.js +40 -0
- package/lib/hooks/use-label-focus.d.ts +11 -0
- package/lib/hooks/use-label-focus.js +28 -0
- package/lib/hooks/use-multi-option-serialization.d.ts +10 -0
- package/lib/hooks/use-multi-option-serialization.js +82 -0
- package/lib/hooks/use-option-serialization.d.ts +10 -0
- package/lib/hooks/use-option-serialization.js +59 -0
- package/lib/index.css +1700 -705
- package/lib/index.d.ts +4 -6
- package/lib/index.js +3 -3
- package/lib/multiselect.d.ts +29 -0
- package/lib/multiselect.js +239 -0
- package/lib/native-select.d.ts +4 -0
- package/lib/native-select.js +182 -0
- package/lib/parts/foldable.js +5 -7
- package/lib/parts/form-trigger-wrapper.d.ts +21 -3
- package/lib/parts/form-trigger-wrapper.js +30 -40
- package/lib/parts/icons.d.ts +17 -0
- package/lib/parts/icons.js +75 -0
- package/lib/parts/list-box.d.ts +19 -0
- package/lib/parts/list-box.js +146 -0
- package/lib/parts/multi-trigger.d.ts +11 -0
- package/lib/parts/multi-trigger.js +62 -0
- package/lib/parts/native-select-options-with-groups.d.ts +8 -0
- package/lib/parts/native-select-options-with-groups.js +76 -0
- package/lib/parts/native-select-trigger.d.ts +18 -0
- package/lib/parts/native-select-trigger.js +54 -0
- package/lib/parts/popover.d.ts +12 -0
- package/lib/parts/popover.js +62 -0
- package/lib/parts/popup-content.d.ts +19 -0
- package/lib/parts/popup-content.js +76 -0
- package/lib/public-api.p.css +401 -1022
- package/lib/public-api.pcss +401 -1022
- package/lib/select-basic.d.ts +3 -0
- package/lib/select-basic.js +143 -0
- package/lib/select-searchable.d.ts +3 -0
- package/lib/select-searchable.js +168 -0
- package/lib/select.d.ts +27 -86
- package/lib/select.js +58 -352
- package/lib/styles/common.p.module.css.js +27 -0
- package/lib/styles/form-trigger.p.module.css.js +15 -0
- package/lib/styles/list-box.p.module.css.js +16 -0
- package/lib/styles/native-select-trigger.p.module.css.js +17 -0
- package/lib/styles/native-select.p.module.css.js +9 -0
- package/lib/styles/popover.p.module.css.js +10 -0
- package/lib/types.d.ts +167 -4
- package/lib/utils/calculate-max-height-by-items.d.ts +13 -0
- package/lib/utils/calculate-max-height-by-items.js +22 -0
- package/lib/utils/convert-options.d.ts +3 -0
- package/lib/utils/convert-options.js +52 -0
- package/lib/utils/convert-placement.d.ts +3 -0
- package/lib/utils/convert-placement.js +22 -0
- package/lib/utils/css-vars-utils.d.ts +3 -0
- package/lib/utils/css-vars-utils.js +20 -0
- package/lib/utils/get-empty-message.d.ts +6 -0
- package/lib/utils/get-empty-message.js +32 -0
- package/lib/utils/get-option-value.d.ts +2 -0
- package/lib/utils/get-option-value.js +11 -0
- package/lib/utils/get-real-items-cnt.d.ts +2 -0
- package/lib/utils/get-real-items-cnt.js +21 -0
- package/lib/utils/get-text-from-nodes.d.ts +2 -0
- package/lib/utils/get-text-from-nodes.js +28 -0
- package/lib/utils/is-option-a-group.d.ts +2 -0
- package/lib/utils/is-option-a-group.js +5 -0
- package/lib/utils/throttle.d.ts +1 -0
- package/package.json +12 -8
- package/lib/_virtual/warning.js +0 -106
- package/lib/key-codes.d.ts +0 -7
- package/lib/key-codes.js +0 -8
- package/lib/parts/common-select.p.module.css.js +0 -15
- package/lib/parts/form-trigger.p.module.css.js +0 -13
- package/lib/parts/multiselect.d.ts +0 -81
- package/lib/parts/multiselect.js +0 -441
- package/lib/parts/native-select.d.ts +0 -30
- package/lib/parts/native-select.js +0 -244
- package/lib/parts/native-select.p.module.css.js +0 -9
- package/lib/parts/throttle.d.ts +0 -1
- package/lib/parts/trigger.d.ts +0 -37
- package/lib/parts/trigger.js +0 -255
- package/lib/parts/trigger.p.module.css.js +0 -31
- package/lib/utils.d.ts +0 -22
- package/lib/utils.js +0 -201
- /package/lib/{parts → hooks}/use-observable-force-rerender.d.ts +0 -0
- /package/lib/{parts → hooks}/use-observable-force-rerender.js +0 -0
- /package/lib/{parts → utils}/throttle.js +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { useFocusRing } from 'react-aria';
|
|
4
|
+
import CloseOutlineIcon from '../_virtual/close-outline.js';
|
|
5
|
+
import LoadingOutlineIcon from '../_virtual/loading-outline.js';
|
|
6
|
+
import DownOutlineIcon from '../_virtual/down-outline.js';
|
|
7
|
+
import styles from '../styles/common.p.module.css.js';
|
|
8
|
+
|
|
9
|
+
const ClearOrLoading = _ref => {
|
|
10
|
+
let {
|
|
11
|
+
isLoading,
|
|
12
|
+
canHaveClearIcon,
|
|
13
|
+
onClearClick,
|
|
14
|
+
triggerId,
|
|
15
|
+
className
|
|
16
|
+
} = _ref;
|
|
17
|
+
const {
|
|
18
|
+
isFocusVisible,
|
|
19
|
+
focusProps
|
|
20
|
+
} = useFocusRing();
|
|
21
|
+
|
|
22
|
+
if (isLoading) {
|
|
23
|
+
return /*#__PURE__*/React.createElement(LoadingOutlineIcon, {
|
|
24
|
+
style: {
|
|
25
|
+
pointerEvents: 'none'
|
|
26
|
+
},
|
|
27
|
+
className: cn(className, styles.icon),
|
|
28
|
+
"data-test": "loading-icon",
|
|
29
|
+
"data-render-all-sizes": true
|
|
30
|
+
});
|
|
31
|
+
} else if (canHaveClearIcon) {
|
|
32
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
33
|
+
type: "button",
|
|
34
|
+
className: cn(className, styles.icon, styles.clearIcon, isFocusVisible && styles.clearIconFocusVisible),
|
|
35
|
+
"data-test": "clear-icon",
|
|
36
|
+
onClick: e => {
|
|
37
|
+
e.stopPropagation();
|
|
38
|
+
onClearClick();
|
|
39
|
+
},
|
|
40
|
+
onPointerDown: e => e.stopPropagation(),
|
|
41
|
+
onMouseDown: e => e.stopPropagation(),
|
|
42
|
+
onKeyDown: e => e.stopPropagation(),
|
|
43
|
+
"aria-label": "Clear",
|
|
44
|
+
"aria-controls": triggerId,
|
|
45
|
+
...focusProps
|
|
46
|
+
}, /*#__PURE__*/React.createElement(CloseOutlineIcon, {
|
|
47
|
+
"data-render-all-sizes": true
|
|
48
|
+
}));
|
|
49
|
+
} else {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const Icons = _ref2 => {
|
|
55
|
+
let {
|
|
56
|
+
isLoading,
|
|
57
|
+
canHaveClearIcon,
|
|
58
|
+
onClear,
|
|
59
|
+
triggerId
|
|
60
|
+
} = _ref2;
|
|
61
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
62
|
+
className: styles.iconsWrapper
|
|
63
|
+
}, /*#__PURE__*/React.createElement(ClearOrLoading, {
|
|
64
|
+
isLoading: isLoading,
|
|
65
|
+
canHaveClearIcon: canHaveClearIcon,
|
|
66
|
+
onClearClick: onClear,
|
|
67
|
+
triggerId: triggerId
|
|
68
|
+
}), /*#__PURE__*/React.createElement(DownOutlineIcon, {
|
|
69
|
+
className: styles.toggle,
|
|
70
|
+
"data-test": "toggle-icon",
|
|
71
|
+
"data-render-all-sizes": true
|
|
72
|
+
}));
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export { ClearOrLoading, Icons };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AriaListBoxOptions } from 'react-aria';
|
|
3
|
+
import type { ListState } from 'react-stately';
|
|
4
|
+
import type { SelectSize, SelectMode } from '../types';
|
|
5
|
+
export declare type ListBoxProps<T extends object> = {
|
|
6
|
+
listBoxRef?: React.RefObject<HTMLUListElement>;
|
|
7
|
+
state: ListState<T>;
|
|
8
|
+
ariaListBoxProps?: AriaListBoxOptions<T>;
|
|
9
|
+
size?: SelectSize;
|
|
10
|
+
mode?: SelectMode;
|
|
11
|
+
className?: string;
|
|
12
|
+
maxVisibleItems?: number;
|
|
13
|
+
selectionMode?: 'single' | 'multiple';
|
|
14
|
+
};
|
|
15
|
+
export declare function ListBox<T extends object>({ listBoxRef: listBoxRefFromProps, state, ariaListBoxProps, size, mode, maxVisibleItems, selectionMode }: ListBoxProps<T>): JSX.Element;
|
|
16
|
+
export declare type EmptyListBoxProps<T extends object> = {
|
|
17
|
+
emptyListMessage: string;
|
|
18
|
+
} & Omit<ListBoxProps<T>, 'state'>;
|
|
19
|
+
export declare const EmptyListBox: <T extends object>({ emptyListMessage, ...props }: EmptyListBoxProps<T>) => JSX.Element;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { useListState, Item } from 'react-stately';
|
|
4
|
+
import { useListBox, useOption, mergeProps, useListBoxSection } from 'react-aria';
|
|
5
|
+
import styles from '../styles/list-box.p.module.css.js';
|
|
6
|
+
import { calculateMaxHeightByItems } from '../utils/calculate-max-height-by-items.js';
|
|
7
|
+
import { getRealItemsCnt } from '../utils/get-real-items-cnt.js';
|
|
8
|
+
import { VIRTUAL_ITEMS_SECTION_KEY } from '../constants.js';
|
|
9
|
+
import CheckOutlineIcon from '../_virtual/check-outline.js';
|
|
10
|
+
const MODE_STYLES = {
|
|
11
|
+
classic: styles.modeClassic,
|
|
12
|
+
rock: styles.modeRock
|
|
13
|
+
};
|
|
14
|
+
const SIZE_STYLES = {
|
|
15
|
+
s: styles.sizeS,
|
|
16
|
+
m: styles.sizeM,
|
|
17
|
+
l: styles.sizeL
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function Option(_ref) {
|
|
21
|
+
let {
|
|
22
|
+
item,
|
|
23
|
+
state,
|
|
24
|
+
selectionMode
|
|
25
|
+
} = _ref;
|
|
26
|
+
// Get props for the option element
|
|
27
|
+
const ref = useRef(null);
|
|
28
|
+
const {
|
|
29
|
+
optionProps,
|
|
30
|
+
isSelected,
|
|
31
|
+
isFocused,
|
|
32
|
+
isDisabled
|
|
33
|
+
} = useOption({
|
|
34
|
+
key: item.key
|
|
35
|
+
}, state, ref);
|
|
36
|
+
return /*#__PURE__*/React.createElement("li", { ...mergeProps(optionProps),
|
|
37
|
+
ref: ref,
|
|
38
|
+
className: cn(styles.item, isSelected && styles.selected, isDisabled && styles.disabled),
|
|
39
|
+
"data-rs-internal": "select-list-box__item",
|
|
40
|
+
"data-focused": isFocused,
|
|
41
|
+
"data-test": `select-options-list__item_${item.key}`
|
|
42
|
+
}, /*#__PURE__*/React.createElement("span", null, item.rendered), selectionMode === 'multiple' && /*#__PURE__*/React.createElement(CheckOutlineIcon, {
|
|
43
|
+
"data-rs-internal": "select-list-box__check-icon",
|
|
44
|
+
className: cn(styles.checkIcon, isSelected && styles.visible)
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function ListBoxSection(_ref2) {
|
|
49
|
+
let {
|
|
50
|
+
section,
|
|
51
|
+
state,
|
|
52
|
+
isFirst,
|
|
53
|
+
selectionMode
|
|
54
|
+
} = _ref2;
|
|
55
|
+
const {
|
|
56
|
+
itemProps,
|
|
57
|
+
headingProps,
|
|
58
|
+
groupProps
|
|
59
|
+
} = useListBoxSection({
|
|
60
|
+
heading: section.rendered,
|
|
61
|
+
'aria-label': section['aria-label']
|
|
62
|
+
});
|
|
63
|
+
const hasHeading = section.rendered !== null && section.rendered !== undefined;
|
|
64
|
+
const hasDivider = !isFirst && !hasHeading; // If the section is not the first, add a divider for visual separation
|
|
65
|
+
|
|
66
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, hasDivider && /*#__PURE__*/React.createElement("hr", {
|
|
67
|
+
className: styles.divider
|
|
68
|
+
}), /*#__PURE__*/React.createElement("li", { ...itemProps
|
|
69
|
+
}, hasHeading && /*#__PURE__*/React.createElement("span", {
|
|
70
|
+
className: styles.groupHeader,
|
|
71
|
+
...headingProps,
|
|
72
|
+
"data-rs-internal": "select-list-box__group-header"
|
|
73
|
+
}, section.rendered), /*#__PURE__*/React.createElement("ul", { ...groupProps,
|
|
74
|
+
style: {
|
|
75
|
+
padding: 0,
|
|
76
|
+
listStyle: 'none'
|
|
77
|
+
}
|
|
78
|
+
}, [...state.collection.getChildren(section.key)].map(node => /*#__PURE__*/React.createElement(Option, {
|
|
79
|
+
key: node.key,
|
|
80
|
+
item: node,
|
|
81
|
+
state: state,
|
|
82
|
+
selectionMode: selectionMode
|
|
83
|
+
})))));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function ListBox(_ref3) {
|
|
87
|
+
var _items$find;
|
|
88
|
+
|
|
89
|
+
let {
|
|
90
|
+
listBoxRef: listBoxRefFromProps,
|
|
91
|
+
state,
|
|
92
|
+
ariaListBoxProps,
|
|
93
|
+
size,
|
|
94
|
+
mode,
|
|
95
|
+
maxVisibleItems = 5,
|
|
96
|
+
selectionMode
|
|
97
|
+
} = _ref3;
|
|
98
|
+
const ref = useRef(null);
|
|
99
|
+
const listBoxRef = listBoxRefFromProps ?? ref;
|
|
100
|
+
const {
|
|
101
|
+
listBoxProps
|
|
102
|
+
} = useListBox(ariaListBoxProps, state, listBoxRef);
|
|
103
|
+
const items = [...state.collection].filter(item => item.key !== VIRTUAL_ITEMS_SECTION_KEY);
|
|
104
|
+
const firstSectionKey = (_items$find = items.find(item => item.type === 'section')) === null || _items$find === void 0 ? void 0 : _items$find.key;
|
|
105
|
+
const itemsCount = getRealItemsCnt(state);
|
|
106
|
+
return /*#__PURE__*/React.createElement("ul", { ...listBoxProps,
|
|
107
|
+
className: cn(styles.listBox, MODE_STYLES[mode], SIZE_STYLES[size]),
|
|
108
|
+
ref: listBoxRef,
|
|
109
|
+
style: {
|
|
110
|
+
'--_rs-select-list-box-max-height-by-items': calculateMaxHeightByItems(itemsCount, maxVisibleItems)
|
|
111
|
+
},
|
|
112
|
+
"data-rs-internal": "select-list-box",
|
|
113
|
+
"data-test": "select-options-list"
|
|
114
|
+
}, items.map(item => item.type === 'section' ? /*#__PURE__*/React.createElement(ListBoxSection, {
|
|
115
|
+
key: item.key,
|
|
116
|
+
section: item,
|
|
117
|
+
state: state,
|
|
118
|
+
isFirst: item.key === firstSectionKey,
|
|
119
|
+
selectionMode: selectionMode
|
|
120
|
+
}) : /*#__PURE__*/React.createElement(Option, {
|
|
121
|
+
key: item.key,
|
|
122
|
+
item: item,
|
|
123
|
+
state: state,
|
|
124
|
+
selectionMode: selectionMode
|
|
125
|
+
})));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const EmptyListBox = _ref4 => {
|
|
129
|
+
let {
|
|
130
|
+
emptyListMessage,
|
|
131
|
+
...props
|
|
132
|
+
} = _ref4;
|
|
133
|
+
const emptyListState = useListState({
|
|
134
|
+
children: [/*#__PURE__*/React.createElement(Item, {
|
|
135
|
+
key: "no-results",
|
|
136
|
+
textValue: emptyListMessage
|
|
137
|
+
}, emptyListMessage)],
|
|
138
|
+
disabledKeys: ['no-results'],
|
|
139
|
+
selectionMode: 'none'
|
|
140
|
+
});
|
|
141
|
+
return /*#__PURE__*/React.createElement(ListBox, { ...props,
|
|
142
|
+
state: emptyListState
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export { EmptyListBox, ListBox };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SelectState } from 'react-stately';
|
|
3
|
+
export interface MultiTriggerProps<T extends object> {
|
|
4
|
+
state: SelectState<T, 'multiple'>;
|
|
5
|
+
valueProps: object;
|
|
6
|
+
isSingleLine: boolean;
|
|
7
|
+
isDisabled: boolean;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
triggerRef?: React.RefObject<HTMLDivElement>;
|
|
10
|
+
}
|
|
11
|
+
export declare function MultiTrigger<T extends object>({ state, valueProps, isSingleLine, isDisabled, placeholder, triggerRef }: MultiTriggerProps<T>): JSX.Element;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { RemovableTag, Tag } from '@rescui/tag';
|
|
4
|
+
import styles from '../styles/common.p.module.css.js';
|
|
5
|
+
import { getTextFromNodes } from '../utils/get-text-from-nodes.js';
|
|
6
|
+
import Foldable from './foldable.js';
|
|
7
|
+
|
|
8
|
+
function MultiTrigger(_ref) {
|
|
9
|
+
let {
|
|
10
|
+
state,
|
|
11
|
+
valueProps,
|
|
12
|
+
isSingleLine,
|
|
13
|
+
isDisabled,
|
|
14
|
+
placeholder,
|
|
15
|
+
triggerRef
|
|
16
|
+
} = _ref;
|
|
17
|
+
const hasValue = state.selectedItems.length > 0;
|
|
18
|
+
|
|
19
|
+
if (!hasValue) {
|
|
20
|
+
return /*#__PURE__*/React.createElement("div", { ...valueProps,
|
|
21
|
+
className: cn(styles.triggerText, styles.labelNotSelected),
|
|
22
|
+
"data-test": 'multiselect__trigger_content'
|
|
23
|
+
}, placeholder);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const handleRemoveItem = key => {
|
|
27
|
+
var _triggerRef$current;
|
|
28
|
+
|
|
29
|
+
state.setValue([...state.selectedItems].map(item => item.key).filter(itemKey => itemKey !== key));
|
|
30
|
+
(_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const tags = [...state.selectedItems].map(item => {
|
|
34
|
+
const key = item.key;
|
|
35
|
+
return /*#__PURE__*/React.createElement(RemovableTag, {
|
|
36
|
+
key: key,
|
|
37
|
+
"data-test": `selected-tag-${key}`,
|
|
38
|
+
className: styles.tag,
|
|
39
|
+
disabled: isDisabled,
|
|
40
|
+
onRemoveClick: () => handleRemoveItem(key),
|
|
41
|
+
"data-rs-internal": "select-trigger__removable-tag",
|
|
42
|
+
wrap: !isSingleLine,
|
|
43
|
+
"aria-label": getTextFromNodes(item.rendered)
|
|
44
|
+
}, item.rendered);
|
|
45
|
+
});
|
|
46
|
+
return /*#__PURE__*/React.createElement("div", { ...valueProps,
|
|
47
|
+
className: styles.multi,
|
|
48
|
+
"data-test": "multiselect__trigger_content"
|
|
49
|
+
}, isSingleLine ? /*#__PURE__*/React.createElement(Foldable, {
|
|
50
|
+
className: styles.tagsContainer,
|
|
51
|
+
renderHiddenCounter: (n, ref) => /*#__PURE__*/React.createElement(Tag, {
|
|
52
|
+
className: cn(styles.tag, styles.filledTag),
|
|
53
|
+
key: "+",
|
|
54
|
+
ref: ref,
|
|
55
|
+
"data-rs-internal": "select-trigger__tag"
|
|
56
|
+
}, "+", n)
|
|
57
|
+
}, tags) : /*#__PURE__*/React.createElement("div", {
|
|
58
|
+
className: styles.tagsContainer
|
|
59
|
+
}, tags));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { MultiTrigger };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { NativeSelectOptionOrGroup } from '../types';
|
|
3
|
+
export declare type NativeSelectOptionsWithGroupsProps = {
|
|
4
|
+
optionsWithGroups: NativeSelectOptionOrGroup[];
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
emptyListMessage?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const NativeSelectOptionsWithGroups: React.FC<NativeSelectOptionsWithGroupsProps>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { NO_OPTIONS_VALUE } from '../constants.js';
|
|
3
|
+
import { isOptionAGroup } from '../utils/is-option-a-group.js';
|
|
4
|
+
|
|
5
|
+
const collectOptionGroupValues = options => options.map(_ref => {
|
|
6
|
+
let {
|
|
7
|
+
value
|
|
8
|
+
} = _ref;
|
|
9
|
+
return value;
|
|
10
|
+
}).join('-');
|
|
11
|
+
|
|
12
|
+
const Option = _ref2 => {
|
|
13
|
+
let {
|
|
14
|
+
value,
|
|
15
|
+
label,
|
|
16
|
+
disabled = false
|
|
17
|
+
} = _ref2;
|
|
18
|
+
return /*#__PURE__*/React.createElement("option", {
|
|
19
|
+
value: value,
|
|
20
|
+
disabled: disabled
|
|
21
|
+
}, label);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const OptionGroup = _ref3 => {
|
|
25
|
+
let {
|
|
26
|
+
options = [],
|
|
27
|
+
label = '',
|
|
28
|
+
disabled = false
|
|
29
|
+
} = _ref3;
|
|
30
|
+
return /*#__PURE__*/React.createElement("optgroup", {
|
|
31
|
+
label: label,
|
|
32
|
+
disabled: disabled
|
|
33
|
+
}, options.map(option => /*#__PURE__*/React.createElement(Option, {
|
|
34
|
+
key: option.value,
|
|
35
|
+
value: option.value,
|
|
36
|
+
label: option.label,
|
|
37
|
+
disabled: option.disabled
|
|
38
|
+
})));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const NativeSelectOptionsWithGroups = _ref4 => {
|
|
42
|
+
let {
|
|
43
|
+
optionsWithGroups,
|
|
44
|
+
placeholder,
|
|
45
|
+
emptyListMessage
|
|
46
|
+
} = _ref4;
|
|
47
|
+
const hasOptions = optionsWithGroups.length > 0;
|
|
48
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("option", {
|
|
49
|
+
value: '',
|
|
50
|
+
disabled: true,
|
|
51
|
+
hidden: true
|
|
52
|
+
}, hasOptions ? placeholder : emptyListMessage), !hasOptions && /*#__PURE__*/React.createElement("option", {
|
|
53
|
+
value: NO_OPTIONS_VALUE,
|
|
54
|
+
disabled: true
|
|
55
|
+
}, emptyListMessage), optionsWithGroups.map(optionOrGroup => {
|
|
56
|
+
if (isOptionAGroup(optionOrGroup)) {
|
|
57
|
+
const group = optionOrGroup;
|
|
58
|
+
return /*#__PURE__*/React.createElement(OptionGroup, {
|
|
59
|
+
key: `group--${group.label}--${collectOptionGroupValues(group.options)}`,
|
|
60
|
+
options: group.options,
|
|
61
|
+
disabled: group.disabled,
|
|
62
|
+
label: group.label
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const option = optionOrGroup;
|
|
67
|
+
return /*#__PURE__*/React.createElement(Option, {
|
|
68
|
+
key: option.value,
|
|
69
|
+
value: option.value,
|
|
70
|
+
label: option.label,
|
|
71
|
+
disabled: option.disabled
|
|
72
|
+
});
|
|
73
|
+
}));
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export { NativeSelectOptionsWithGroups };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { Theme } from '@rescui/ui-contexts';
|
|
3
|
+
import { Key, SelectSize } from '../types';
|
|
4
|
+
export declare type NativeSelectDefaultTriggerProps = {
|
|
5
|
+
isFocused: boolean;
|
|
6
|
+
isHovered: boolean;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
isDisabled: boolean;
|
|
9
|
+
size: SelectSize;
|
|
10
|
+
theme?: Theme;
|
|
11
|
+
hasError: boolean;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
value: {
|
|
14
|
+
value?: Key;
|
|
15
|
+
label: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare const NativeSelectTrigger: ({ isFocused, isHovered, isLoading, isDisabled, hasError, size, theme, placeholder, value }: NativeSelectDefaultTriggerProps) => JSX.Element;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import LoadingOutlineIcon from '../_virtual/loading-outline.js';
|
|
4
|
+
import DownOutlineIcon from '../_virtual/down-outline.js';
|
|
5
|
+
import styles from '../styles/native-select-trigger.p.module.css.js';
|
|
6
|
+
const SIZE_STYLES = {
|
|
7
|
+
s: styles.sizeS,
|
|
8
|
+
m: styles.sizeM,
|
|
9
|
+
l: styles.sizeL
|
|
10
|
+
};
|
|
11
|
+
const THEME_STYLES = {
|
|
12
|
+
light: styles.themeLight,
|
|
13
|
+
dark: styles.themeDark
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const NativeSelectTrigger = _ref => {
|
|
17
|
+
let {
|
|
18
|
+
isFocused,
|
|
19
|
+
isHovered,
|
|
20
|
+
isLoading,
|
|
21
|
+
isDisabled,
|
|
22
|
+
hasError,
|
|
23
|
+
size,
|
|
24
|
+
theme,
|
|
25
|
+
placeholder,
|
|
26
|
+
value
|
|
27
|
+
} = _ref;
|
|
28
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
29
|
+
"aria-hidden": "true",
|
|
30
|
+
className: cn(styles.trigger, SIZE_STYLES[size], THEME_STYLES[theme], isDisabled ? styles.disabled : styles.enabled, hasError && styles.error),
|
|
31
|
+
"data-focused": isFocused,
|
|
32
|
+
"data-hovered": isHovered,
|
|
33
|
+
"data-test": 'native-select_trigger',
|
|
34
|
+
"data-rs-internal": 'select-native-trigger'
|
|
35
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
36
|
+
className: cn(styles.triggerText, !(value !== null && value !== void 0 && value.value) && styles.labelNotSelected),
|
|
37
|
+
"data-test": 'native-select_trigger_text'
|
|
38
|
+
}, (value === null || value === void 0 ? void 0 : value.label) ?? placeholder), /*#__PURE__*/React.createElement("div", {
|
|
39
|
+
className: styles.iconsWrapper
|
|
40
|
+
}, isLoading && /*#__PURE__*/React.createElement(LoadingOutlineIcon, {
|
|
41
|
+
style: {
|
|
42
|
+
pointerEvents: 'none'
|
|
43
|
+
},
|
|
44
|
+
className: styles.icon,
|
|
45
|
+
"data-test": "loading-icon",
|
|
46
|
+
"data-render-all-sizes": true
|
|
47
|
+
}), /*#__PURE__*/React.createElement(DownOutlineIcon, {
|
|
48
|
+
className: styles.toggle,
|
|
49
|
+
"data-test": "down-icon",
|
|
50
|
+
"data-render-all-sizes": true
|
|
51
|
+
})));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export { NativeSelectTrigger };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AriaPopoverProps } from 'react-aria';
|
|
3
|
+
import type { OverlayTriggerState } from 'react-stately';
|
|
4
|
+
import type { SelectMode } from '../types';
|
|
5
|
+
export interface PopoverProps extends Omit<AriaPopoverProps, 'popoverRef' | 'isNonModal'> {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
state: OverlayTriggerState;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
popoverRef?: React.RefObject<HTMLDivElement | null>;
|
|
10
|
+
mode?: SelectMode;
|
|
11
|
+
}
|
|
12
|
+
export declare function Popover({ children, state, style, triggerRef, mode, ...props }: PopoverProps): JSX.Element;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { usePopover, useInteractOutside, Overlay, mergeProps, DismissButton } from 'react-aria';
|
|
4
|
+
import styles from '../styles/popover.p.module.css.js';
|
|
5
|
+
const MODE_STYLES = {
|
|
6
|
+
classic: styles.classic,
|
|
7
|
+
rock: styles.rock
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function Popover(_ref) {
|
|
11
|
+
let {
|
|
12
|
+
children,
|
|
13
|
+
state,
|
|
14
|
+
style,
|
|
15
|
+
triggerRef,
|
|
16
|
+
mode,
|
|
17
|
+
...props
|
|
18
|
+
} = _ref;
|
|
19
|
+
const popoverRefLocal = useRef(null);
|
|
20
|
+
const popoverRef = props.popoverRef ?? popoverRefLocal;
|
|
21
|
+
const {
|
|
22
|
+
popoverProps,
|
|
23
|
+
placement: realPlacement
|
|
24
|
+
} = usePopover({ ...props,
|
|
25
|
+
offset: 8,
|
|
26
|
+
popoverRef,
|
|
27
|
+
triggerRef,
|
|
28
|
+
isNonModal: true
|
|
29
|
+
}, state);
|
|
30
|
+
useInteractOutside({
|
|
31
|
+
ref: popoverRef,
|
|
32
|
+
onInteractOutside: state.close
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const handleKeyDown = e => {
|
|
36
|
+
// Block default browser behavior for arrow keys
|
|
37
|
+
// This will prevent the page from scrolling when we focus on the edges of the list.
|
|
38
|
+
// Relevant only for useSelect usage
|
|
39
|
+
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return /*#__PURE__*/React.createElement(Overlay, null, /*#__PURE__*/React.createElement("div", { ...mergeProps(popoverProps, {
|
|
45
|
+
onKeyDown: handleKeyDown
|
|
46
|
+
}),
|
|
47
|
+
ref: popoverRef,
|
|
48
|
+
className: cn(styles.popover, MODE_STYLES[mode]),
|
|
49
|
+
style: { ...popoverProps.style,
|
|
50
|
+
...style
|
|
51
|
+
},
|
|
52
|
+
"data-popover-placement": realPlacement
|
|
53
|
+
}, /*#__PURE__*/React.createElement(DismissButton, {
|
|
54
|
+
onDismiss: state.close
|
|
55
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
56
|
+
className: styles.contentWrapper
|
|
57
|
+
}, children), /*#__PURE__*/React.createElement(DismissButton, {
|
|
58
|
+
onDismiss: state.close
|
|
59
|
+
})));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { Popover };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AriaListBoxOptions } from 'react-aria';
|
|
3
|
+
import type { Theme } from '@rescui/ui-contexts';
|
|
4
|
+
import type { CommonState, SelectMode, SelectSize, AriaPlacement } from '../types';
|
|
5
|
+
export declare type PopupContentProps<T extends object> = {
|
|
6
|
+
theme: Theme;
|
|
7
|
+
state: CommonState<T>;
|
|
8
|
+
triggerRef: React.RefObject<HTMLElement>;
|
|
9
|
+
popoverRef?: React.RefObject<HTMLDivElement>;
|
|
10
|
+
listBoxRef?: React.RefObject<HTMLUListElement>;
|
|
11
|
+
placement: AriaPlacement;
|
|
12
|
+
size?: SelectSize;
|
|
13
|
+
mode?: SelectMode;
|
|
14
|
+
listBoxProps: AriaListBoxOptions<T>;
|
|
15
|
+
emptyListMessage: string;
|
|
16
|
+
maxVisibleItems?: number;
|
|
17
|
+
selectionMode?: 'single' | 'multiple';
|
|
18
|
+
};
|
|
19
|
+
export declare const PopupContent: <T extends object>({ theme: themeFromProps, state, triggerRef, popoverRef, listBoxRef, placement, size: sizeFromProps, mode, listBoxProps, emptyListMessage, maxVisibleItems, selectionMode }: PopupContentProps<T>) => JSX.Element;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useResizeObserver } from '@rescui/use-resize-observer';
|
|
3
|
+
import { useObservableForceRerender } from '../hooks/use-observable-force-rerender.js';
|
|
4
|
+
import { useCssContextTransfer } from '../hooks/use-css-context-transfer.js';
|
|
5
|
+
import { getRealItemsCnt } from '../utils/get-real-items-cnt.js';
|
|
6
|
+
import styles from '../styles/popover.p.module.css.js';
|
|
7
|
+
import { Popover } from './popover.js';
|
|
8
|
+
import { ListBox, EmptyListBox } from './list-box.js'; // eslint-disable-next-line complexity
|
|
9
|
+
|
|
10
|
+
const PopupContent = _ref => {
|
|
11
|
+
let {
|
|
12
|
+
theme: themeFromProps,
|
|
13
|
+
state,
|
|
14
|
+
triggerRef,
|
|
15
|
+
popoverRef,
|
|
16
|
+
listBoxRef,
|
|
17
|
+
placement,
|
|
18
|
+
size: sizeFromProps,
|
|
19
|
+
mode,
|
|
20
|
+
listBoxProps,
|
|
21
|
+
emptyListMessage,
|
|
22
|
+
maxVisibleItems = 5,
|
|
23
|
+
selectionMode
|
|
24
|
+
} = _ref;
|
|
25
|
+
const isOpen = state.isOpen;
|
|
26
|
+
const [triggerWidth, setTriggerWidth] = React.useState(null);
|
|
27
|
+
useResizeObserver(triggerRef, () => {
|
|
28
|
+
setTriggerWidth(`${triggerRef.current.offsetWidth}px`);
|
|
29
|
+
}); // We use invisible and "untouchable" dummy element to observe `size` changes from css to trigger force rerenders
|
|
30
|
+
|
|
31
|
+
const observableRef = useObservableForceRerender();
|
|
32
|
+
const {
|
|
33
|
+
theme,
|
|
34
|
+
size,
|
|
35
|
+
primaryColors
|
|
36
|
+
} = useCssContextTransfer({
|
|
37
|
+
triggerRef,
|
|
38
|
+
isOpen,
|
|
39
|
+
themeFromProps,
|
|
40
|
+
sizeFromProps
|
|
41
|
+
});
|
|
42
|
+
const isEmpty = getRealItemsCnt(state) === 0;
|
|
43
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
44
|
+
ref: observableRef,
|
|
45
|
+
className: styles.observable
|
|
46
|
+
}), isOpen && /*#__PURE__*/React.createElement(Popover, {
|
|
47
|
+
state: state,
|
|
48
|
+
triggerRef: triggerRef,
|
|
49
|
+
popoverRef: popoverRef,
|
|
50
|
+
placement: placement,
|
|
51
|
+
style: {
|
|
52
|
+
'--_rs-select-trigger-width': triggerWidth || 'auto',
|
|
53
|
+
'--rs-theme-dark': theme === 'dark' ? '1' : '0',
|
|
54
|
+
...primaryColors
|
|
55
|
+
},
|
|
56
|
+
mode: mode
|
|
57
|
+
}, !isEmpty ? /*#__PURE__*/React.createElement(ListBox, {
|
|
58
|
+
listBoxRef: listBoxRef,
|
|
59
|
+
ariaListBoxProps: listBoxProps,
|
|
60
|
+
size: size,
|
|
61
|
+
mode: mode,
|
|
62
|
+
state: state,
|
|
63
|
+
maxVisibleItems: maxVisibleItems,
|
|
64
|
+
selectionMode: selectionMode
|
|
65
|
+
}) : /*#__PURE__*/React.createElement(EmptyListBox, {
|
|
66
|
+
listBoxRef: listBoxRef,
|
|
67
|
+
ariaListBoxProps: listBoxProps,
|
|
68
|
+
size: size,
|
|
69
|
+
mode: mode,
|
|
70
|
+
emptyListMessage: emptyListMessage,
|
|
71
|
+
maxVisibleItems: maxVisibleItems,
|
|
72
|
+
selectionMode: selectionMode
|
|
73
|
+
})));
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export { PopupContent };
|