@rescui/select 0.15.0 → 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.
Files changed (92) hide show
  1. package/lib/_virtual/index.css.js +12 -12
  2. package/lib/common-prop-types.d.ts +9 -14
  3. package/lib/common-prop-types.js +4 -3
  4. package/lib/constants.d.ts +7 -0
  5. package/lib/constants.js +8 -0
  6. package/lib/hooks/use-css-context-transfer.d.ts +14 -0
  7. package/lib/hooks/use-css-context-transfer.js +40 -0
  8. package/lib/hooks/use-label-focus.d.ts +11 -0
  9. package/lib/hooks/use-label-focus.js +28 -0
  10. package/lib/hooks/use-multi-option-serialization.d.ts +10 -0
  11. package/lib/hooks/use-multi-option-serialization.js +82 -0
  12. package/lib/hooks/use-option-serialization.d.ts +10 -0
  13. package/lib/hooks/use-option-serialization.js +59 -0
  14. package/lib/index.css +2004 -837
  15. package/lib/index.d.ts +4 -6
  16. package/lib/index.js +3 -3
  17. package/lib/multiselect.d.ts +29 -0
  18. package/lib/multiselect.js +239 -0
  19. package/lib/native-select.d.ts +4 -0
  20. package/lib/native-select.js +182 -0
  21. package/lib/parts/foldable.js +5 -7
  22. package/lib/parts/form-trigger-wrapper.d.ts +7 -7
  23. package/lib/parts/form-trigger-wrapper.js +16 -34
  24. package/lib/parts/icons.d.ts +17 -0
  25. package/lib/parts/icons.js +75 -0
  26. package/lib/parts/list-box.d.ts +19 -0
  27. package/lib/parts/list-box.js +146 -0
  28. package/lib/parts/multi-trigger.d.ts +11 -0
  29. package/lib/parts/multi-trigger.js +62 -0
  30. package/lib/parts/native-select-options-with-groups.d.ts +8 -0
  31. package/lib/parts/native-select-options-with-groups.js +76 -0
  32. package/lib/parts/native-select-trigger.d.ts +18 -0
  33. package/lib/parts/native-select-trigger.js +54 -0
  34. package/lib/parts/popover.d.ts +12 -0
  35. package/lib/parts/popover.js +62 -0
  36. package/lib/parts/popup-content.d.ts +19 -0
  37. package/lib/parts/popup-content.js +76 -0
  38. package/lib/public-api.p.css +486 -444
  39. package/lib/public-api.pcss +486 -444
  40. package/lib/select-basic.d.ts +3 -0
  41. package/lib/select-basic.js +143 -0
  42. package/lib/select-searchable.d.ts +3 -0
  43. package/lib/select-searchable.js +168 -0
  44. package/lib/select.d.ts +27 -91
  45. package/lib/select.js +53 -360
  46. package/lib/styles/common.p.module.css.js +27 -0
  47. package/lib/styles/form-trigger.p.module.css.js +15 -0
  48. package/lib/styles/list-box.p.module.css.js +16 -0
  49. package/lib/styles/native-select-trigger.p.module.css.js +17 -0
  50. package/lib/styles/native-select.p.module.css.js +9 -0
  51. package/lib/styles/popover.p.module.css.js +10 -0
  52. package/lib/types.d.ts +167 -4
  53. package/lib/utils/calculate-max-height-by-items.d.ts +13 -0
  54. package/lib/utils/calculate-max-height-by-items.js +22 -0
  55. package/lib/utils/convert-options.d.ts +3 -0
  56. package/lib/utils/convert-options.js +52 -0
  57. package/lib/utils/convert-placement.d.ts +3 -0
  58. package/lib/utils/convert-placement.js +22 -0
  59. package/lib/utils/css-vars-utils.d.ts +3 -0
  60. package/lib/utils/css-vars-utils.js +20 -0
  61. package/lib/utils/get-empty-message.d.ts +6 -0
  62. package/lib/utils/get-empty-message.js +32 -0
  63. package/lib/utils/get-option-value.d.ts +2 -0
  64. package/lib/utils/get-option-value.js +11 -0
  65. package/lib/utils/get-real-items-cnt.d.ts +2 -0
  66. package/lib/utils/get-real-items-cnt.js +21 -0
  67. package/lib/utils/get-text-from-nodes.d.ts +2 -0
  68. package/lib/utils/get-text-from-nodes.js +28 -0
  69. package/lib/utils/is-option-a-group.d.ts +2 -0
  70. package/lib/utils/is-option-a-group.js +5 -0
  71. package/lib/utils/throttle.d.ts +1 -0
  72. package/package.json +14 -11
  73. package/lib/key-codes.d.ts +0 -7
  74. package/lib/key-codes.js +0 -8
  75. package/lib/parts/common-select.p.module.css.js +0 -15
  76. package/lib/parts/form-trigger.p.module.css.js +0 -15
  77. package/lib/parts/multiselect.d.ts +0 -86
  78. package/lib/parts/multiselect.js +0 -455
  79. package/lib/parts/native-select.d.ts +0 -36
  80. package/lib/parts/native-select.js +0 -257
  81. package/lib/parts/native-select.p.module.css.js +0 -9
  82. package/lib/parts/throttle.d.ts +0 -1
  83. package/lib/parts/trigger.d.ts +0 -37
  84. package/lib/parts/trigger.js +0 -255
  85. package/lib/parts/trigger.p.module.css.js +0 -31
  86. package/lib/parts/use-backward-compatible-id.d.ts +0 -4
  87. package/lib/parts/use-backward-compatible-id.js +0 -14
  88. package/lib/utils.d.ts +0 -22
  89. package/lib/utils.js +0 -201
  90. /package/lib/{parts → hooks}/use-observable-force-rerender.d.ts +0 -0
  91. /package/lib/{parts → hooks}/use-observable-force-rerender.js +0 -0
  92. /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 };