@rescui/select 0.15.1-RUI-280-Update-select-component-e516591ed.54 → 0.15.1-RUI-280-Update-select-component-downshift-cd2a98813.66

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 (65) hide show
  1. package/lib/_virtual/index.css.js +12 -12
  2. package/lib/constants.d.ts +0 -1
  3. package/lib/constants.js +1 -2
  4. package/lib/hooks/use-a11y.d.ts +29 -0
  5. package/lib/hooks/use-a11y.js +53 -0
  6. package/lib/hooks/use-backward-compatible-id.d.ts +4 -0
  7. package/lib/hooks/use-backward-compatible-id.js +14 -0
  8. package/lib/hooks/use-label-focus.d.ts +1 -3
  9. package/lib/hooks/use-label-focus.js +3 -9
  10. package/lib/hooks/use-multi-handlers.d.ts +11 -0
  11. package/lib/hooks/use-multi-handlers.js +48 -0
  12. package/lib/hooks/use-options.d.ts +13 -0
  13. package/lib/hooks/use-options.js +89 -0
  14. package/lib/index.css +323 -371
  15. package/lib/multiselect.d.ts +3 -29
  16. package/lib/multiselect.js +249 -171
  17. package/lib/native-select.js +67 -44
  18. package/lib/parts/hidden-select.d.ts +13 -0
  19. package/lib/parts/hidden-select.js +45 -0
  20. package/lib/parts/icons.d.ts +3 -1
  21. package/lib/parts/icons.js +11 -14
  22. package/lib/parts/list-box.d.ts +7 -15
  23. package/lib/parts/list-box.js +50 -80
  24. package/lib/parts/multi-trigger.d.ts +5 -4
  25. package/lib/parts/multi-trigger.js +27 -15
  26. package/lib/parts/native-select-trigger.d.ts +6 -8
  27. package/lib/parts/native-select-trigger.js +14 -23
  28. package/lib/select-basic.d.ts +2 -2
  29. package/lib/select-basic.js +162 -95
  30. package/lib/select-searchable.d.ts +2 -2
  31. package/lib/select-searchable.js +209 -119
  32. package/lib/select.d.ts +1 -1
  33. package/lib/select.js +38 -31
  34. package/lib/styles/common.p.module.css.js +25 -24
  35. package/lib/styles/form-trigger.p.module.css.js +12 -12
  36. package/lib/styles/list-box.p.module.css.js +11 -13
  37. package/lib/styles/native-select-trigger.p.module.css.js +15 -14
  38. package/lib/styles/native-select.p.module.css.js +6 -6
  39. package/lib/types.d.ts +26 -26
  40. package/lib/utils/get-real-items-cnt.d.ts +2 -2
  41. package/lib/utils/get-real-items-cnt.js +8 -10
  42. package/lib/utils/item-to-string.d.ts +2 -0
  43. package/lib/utils/item-to-string.js +7 -0
  44. package/lib/utils/merge-props.d.ts +29 -0
  45. package/lib/utils/merge-props.js +106 -0
  46. package/package.json +12 -8
  47. package/lib/hooks/use-css-context-transfer.d.ts +0 -14
  48. package/lib/hooks/use-css-context-transfer.js +0 -40
  49. package/lib/hooks/use-multi-option-serialization.d.ts +0 -10
  50. package/lib/hooks/use-multi-option-serialization.js +0 -82
  51. package/lib/hooks/use-observable-force-rerender.d.ts +0 -2
  52. package/lib/hooks/use-observable-force-rerender.js +0 -16
  53. package/lib/hooks/use-option-serialization.d.ts +0 -10
  54. package/lib/hooks/use-option-serialization.js +0 -59
  55. package/lib/parts/popover.d.ts +0 -12
  56. package/lib/parts/popover.js +0 -62
  57. package/lib/parts/popup-content.d.ts +0 -19
  58. package/lib/parts/popup-content.js +0 -76
  59. package/lib/styles/popover.p.module.css.js +0 -10
  60. package/lib/utils/convert-options.d.ts +0 -3
  61. package/lib/utils/convert-options.js +0 -52
  62. package/lib/utils/convert-placement.d.ts +0 -3
  63. package/lib/utils/convert-placement.js +0 -22
  64. package/lib/utils/css-vars-utils.d.ts +0 -3
  65. package/lib/utils/css-vars-utils.js +0 -20
@@ -1,82 +0,0 @@
1
- import { useMemo } from 'react';
2
- import { isOptionAGroup } from '../utils/is-option-a-group.js';
3
- import { getOptionValue } from '../utils/get-option-value.js';
4
-
5
- function useMultiOptionSerialization(options, value) {
6
- // Create a map of keys to option objects for O(1) lookup
7
- const optionsMap = useMemo(() => {
8
- const map = new Map();
9
- options.forEach(item => {
10
- if (isOptionAGroup(item)) {
11
- item.options.forEach(option => {
12
- const key = getOptionValue(option);
13
- map.set(key, {
14
- option,
15
- isVirtual: false
16
- });
17
- });
18
- } else {
19
- const key = getOptionValue(item);
20
- map.set(key, {
21
- option: item,
22
- isVirtual: false
23
- });
24
- }
25
- });
26
-
27
- if (value && Array.isArray(value)) {
28
- value.forEach(option => {
29
- const key = getOptionValue(option);
30
-
31
- if (!map.has(key)) {
32
- map.set(key, {
33
- option,
34
- isVirtual: true
35
- });
36
- }
37
- });
38
- }
39
-
40
- return map;
41
- }, [options, value]); // Convert selected option objects array to Set of keys
42
-
43
- const selectedKeys = [];
44
- const virtualOptions = [];
45
-
46
- if (value && Array.isArray(value)) {
47
- value.forEach(option => {
48
- const key = getOptionValue(option);
49
- selectedKeys.push(key);
50
- const {
51
- isVirtual
52
- } = optionsMap.get(key);
53
-
54
- if (isVirtual) {
55
- virtualOptions.push(option);
56
- }
57
- });
58
- } // Helper function to find options by Set of keys
59
-
60
-
61
- const findOptionsByKeys = keys => {
62
- const foundOptions = [];
63
- keys.forEach(key => {
64
- if (optionsMap.has(key)) {
65
- const {
66
- option
67
- } = optionsMap.get(key);
68
- foundOptions.push(option);
69
- }
70
- });
71
- return foundOptions;
72
- };
73
-
74
- return {
75
- optionsMap,
76
- selectedKeys,
77
- findOptionsByKeys,
78
- virtualOptions
79
- };
80
- }
81
-
82
- export { useMultiOptionSerialization };
@@ -1,2 +0,0 @@
1
- /// <reference types="react" />
2
- export declare const useObservableForceRerender: () => import("react").MutableRefObject<HTMLDivElement>;
@@ -1,16 +0,0 @@
1
- import { useRef, useState } from 'react';
2
- import { useResizeObserver } from '@rescui/use-resize-observer';
3
-
4
- const useObservableForceRerender = () => {
5
- const observableRef = useRef(null);
6
- const [, setDummyState] = useState(false);
7
- useResizeObserver(observableRef, () => {
8
- //force rerender
9
- setDummyState(s => !s);
10
- }, {
11
- ignoreFirstCall: true
12
- });
13
- return observableRef;
14
- };
15
-
16
- export { useObservableForceRerender };
@@ -1,10 +0,0 @@
1
- import type { SelectOption, SelectOptionOrGroup, Key } from '../types';
2
- export declare function useOptionSerialization(options: SelectOptionOrGroup[], value?: SelectOption | null): {
3
- optionsMap: Map<Key, {
4
- option: SelectOption;
5
- isVirtual: boolean;
6
- }>;
7
- selectedKey: Key;
8
- findOptionByKey: (key: Key | null) => SelectOption | null;
9
- virtualOption: SelectOption;
10
- };
@@ -1,59 +0,0 @@
1
- import { useMemo } from 'react';
2
- import { isOptionAGroup } from '../utils/is-option-a-group.js';
3
- import { getOptionValue } from '../utils/get-option-value.js';
4
-
5
- function useOptionSerialization(options, value) {
6
- // Create a map of keys to option objects for O(1) lookup
7
- const optionsMap = useMemo(() => {
8
- const map = new Map();
9
- options.forEach(item => {
10
- if (isOptionAGroup(item)) {
11
- item.options.forEach(option => {
12
- const key = getOptionValue(option);
13
- map.set(key, {
14
- option,
15
- isVirtual: false
16
- });
17
- });
18
- } else {
19
- const key = getOptionValue(item);
20
- map.set(key, {
21
- option: item,
22
- isVirtual: false
23
- });
24
- }
25
- });
26
-
27
- if (value) {
28
- const key = getOptionValue(value);
29
-
30
- if (!map.has(key)) {
31
- map.set(key, {
32
- option: value,
33
- isVirtual: true
34
- });
35
- }
36
- }
37
-
38
- return map;
39
- }, [options, value]); // Convert selected option object to key
40
-
41
- const selectedKey = value ? getOptionValue(value) : null;
42
- const virtualOption = value && optionsMap.get(selectedKey).isVirtual ? value : null; // Helper function to find option by key
43
-
44
- const findOptionByKey = key => {
45
- var _optionsMap$get;
46
-
47
- if (key === null) return null;
48
- return ((_optionsMap$get = optionsMap.get(key)) === null || _optionsMap$get === void 0 ? void 0 : _optionsMap$get.option) || null;
49
- };
50
-
51
- return {
52
- optionsMap,
53
- selectedKey,
54
- findOptionByKey,
55
- virtualOption
56
- };
57
- }
58
-
59
- export { useOptionSerialization };
@@ -1,12 +0,0 @@
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;
@@ -1,62 +0,0 @@
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 };
@@ -1,19 +0,0 @@
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;
@@ -1,76 +0,0 @@
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 };
@@ -1,10 +0,0 @@
1
- var styles = {
2
- "classic": "_classic_17wpqx_32",
3
- "rock": "_rock_17wpqx_35",
4
- "popover": "_popover_17wpqx_39",
5
- "contentWrapper": "_contentWrapper_17wpqx_46",
6
- "fadeInBottomToTop": "_fadeInBottomToTop_17wpqx_1",
7
- "fadeInTopToBottom": "_fadeInTopToBottom_17wpqx_1",
8
- "observable": "_observable_17wpqx_62"
9
- };
10
- export { styles as default };
@@ -1,3 +0,0 @@
1
- /// <reference types="react" />
2
- import type { SelectOption, SelectOptionOrGroup } from '../types';
3
- export declare const convertOptions: (options: SelectOptionOrGroup[], virtualOptions: SelectOption[]) => JSX.Element[];
@@ -1,52 +0,0 @@
1
- import React from 'react';
2
- import { Section, Item } from 'react-stately';
3
- import { getOptionValue } from './get-option-value.js';
4
- import { getTextFromNodes } from './get-text-from-nodes.js';
5
- import { isOptionAGroup } from './is-option-a-group.js';
6
- import { VIRTUAL_ITEMS_SECTION_KEY } from '../constants.js';
7
-
8
- const convertOptions = (options, virtualOptions) => [...options.map((item, index) => {
9
- // Check if it's a group
10
- if (isOptionAGroup(item)) {
11
- const group = item;
12
-
13
- if (!group.options || group.options.length === 0) {
14
- return null;
15
- } // Render as Section (with or without label)
16
-
17
-
18
- const groupLabelText = group.label ? getTextFromNodes(group.label) : ''; // Use a special prefix that's unlikely to collide with user values
19
-
20
- const sectionKey = `\0__rs_section_${index}_${groupLabelText}`;
21
- return /*#__PURE__*/React.createElement(Section, {
22
- key: sectionKey,
23
- title: group.label,
24
- "aria-label": groupLabelText || undefined
25
- }, group.options.map(option => {
26
- const key = getOptionValue(option);
27
- return /*#__PURE__*/React.createElement(Item, {
28
- key: key,
29
- textValue: getTextFromNodes(option.label)
30
- }, option.label);
31
- }));
32
- } // It's a single option
33
-
34
-
35
- const option = item;
36
- const key = getOptionValue(option);
37
- return /*#__PURE__*/React.createElement(Item, {
38
- key: key,
39
- textValue: getTextFromNodes(option.label)
40
- }, option.label);
41
- }), virtualOptions.length > 0 && /*#__PURE__*/React.createElement(Section, {
42
- key: VIRTUAL_ITEMS_SECTION_KEY,
43
- title: ''
44
- }, virtualOptions.map(option => {
45
- const key = getOptionValue(option);
46
- return /*#__PURE__*/React.createElement(Item, {
47
- key: key,
48
- textValue: getTextFromNodes(option.label)
49
- }, option.label);
50
- }))].filter(Boolean);
51
-
52
- export { convertOptions };
@@ -1,3 +0,0 @@
1
- import { type AriaPositionProps } from 'react-aria';
2
- import { Placement } from '../types';
3
- export declare const convertPlacement: (outsidePlacement: Placement) => AriaPositionProps['placement'];
@@ -1,22 +0,0 @@
1
- const convertPlacement = outsidePlacement => {
2
- const placementMap = {
3
- top: 'top',
4
- 'top-start': 'top start',
5
- 'top-end': 'top end',
6
- bottom: 'bottom',
7
- 'bottom-start': 'bottom start',
8
- 'bottom-end': 'bottom end',
9
- left: 'left',
10
- 'left-start': 'left top',
11
- 'left-end': 'left bottom',
12
- right: 'right',
13
- 'right-start': 'right top',
14
- 'right-end': 'right bottom',
15
- auto: null,
16
- 'auto-start': 'start',
17
- 'auto-end': 'end'
18
- };
19
- return placementMap[outsidePlacement] || 'bottom';
20
- };
21
-
22
- export { convertPlacement };
@@ -1,3 +0,0 @@
1
- export declare const extractPrimaryColors: (styles: CSSStyleDeclaration) => Record<string, string>;
2
- /** Check out `@rescui/colors/src/public-api.p.css` file */
3
- export declare const extractThemeFromCss: (styles: CSSStyleDeclaration) => "dark" | "light";
@@ -1,20 +0,0 @@
1
- const PRIMARY_COLORS = ['--rs-color-primary-light-theme', '--rs-color-primary-dim-light-theme', '--rs-color-primary-fog-light-theme', '--rs-color-primary-t-dim-light-theme', '--rs-color-primary-t-fog-light-theme', '--rs-color-primary-dark-theme', '--rs-color-primary-dim-dark-theme', '--rs-color-primary-fog-dark-theme', '--rs-color-primary-t-dim-dark-theme', '--rs-color-primary-t-fog-dark-theme'];
2
-
3
- const extractPrimaryColors = styles => {
4
- const colors = {};
5
- PRIMARY_COLORS.forEach(varName => {
6
- colors[varName] = styles.getPropertyValue(varName) || 'initial';
7
- });
8
- return colors;
9
- };
10
- /** Check out `@rescui/colors/src/public-api.p.css` file */
11
-
12
-
13
- const extractThemeFromCss = styles => {
14
- const themeDark = parseInt(styles.getPropertyValue('--rs-theme-dark'), 10) || 0;
15
- const themeFlip = parseInt(styles.getPropertyValue('--rs-theme-flip'), 10) || 0;
16
- const themeDarkCoefficient = themeDark * (1 - themeFlip) + themeFlip * (1 - themeDark);
17
- return themeDarkCoefficient === 1 ? 'dark' : 'light';
18
- };
19
-
20
- export { extractPrimaryColors, extractThemeFromCss };