@rescui/select 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/_virtual/index.css.js +12 -12
- package/lib/common-prop-types.d.ts +8 -14
- package/lib/common-prop-types.js +4 -3
- package/lib/constants.d.ts +6 -0
- package/lib/constants.js +7 -0
- package/lib/hooks/use-a11y.d.ts +30 -0
- package/lib/hooks/use-a11y.js +56 -0
- package/lib/hooks/use-actual-size-from-css.d.ts +10 -0
- package/lib/hooks/use-actual-size-from-css.js +27 -0
- package/lib/hooks/use-focus.d.ts +10 -0
- package/lib/hooks/use-focus.js +17 -0
- package/lib/hooks/use-hover.d.ts +10 -0
- package/lib/hooks/use-hover.js +17 -0
- package/lib/hooks/use-label-focus.d.ts +9 -0
- package/lib/hooks/use-label-focus.js +22 -0
- package/lib/hooks/use-multi-handlers.d.ts +11 -0
- package/lib/hooks/use-multi-handlers.js +44 -0
- package/lib/hooks/use-options.d.ts +14 -0
- package/lib/hooks/use-options.js +90 -0
- package/lib/hooks/use-primary-contrast-css-var-transfer.d.ts +11 -0
- package/lib/hooks/use-primary-contrast-css-var-transfer.js +29 -0
- package/lib/hooks/use-safe-id.d.ts +6 -0
- package/lib/hooks/use-safe-id.js +15 -0
- package/lib/index.css +713 -304
- package/lib/index.d.ts +4 -6
- package/lib/index.js +3 -3
- package/lib/multiselect.d.ts +3 -0
- package/lib/multiselect.js +308 -0
- package/lib/native-select.d.ts +4 -0
- package/lib/native-select.js +208 -0
- package/lib/parts/foldable.js +5 -7
- package/lib/parts/form-trigger-wrapper.d.ts +7 -7
- package/lib/parts/form-trigger-wrapper.js +16 -34
- package/lib/parts/hidden-select.d.ts +13 -0
- package/lib/parts/hidden-select.js +45 -0
- package/lib/parts/icons.d.ts +17 -0
- package/lib/parts/icons.js +69 -0
- package/lib/parts/list-box.d.ts +13 -0
- package/lib/parts/list-box.js +120 -0
- package/lib/parts/multi-trigger.d.ts +12 -0
- package/lib/parts/multi-trigger.js +70 -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/popup-content.d.ts +20 -0
- package/lib/parts/popup-content.js +68 -0
- package/lib/public-api.p.css +543 -307
- package/lib/public-api.pcss +543 -307
- package/lib/select-basic.d.ts +3 -0
- package/lib/select-basic.js +204 -0
- package/lib/select-searchable.d.ts +3 -0
- package/lib/select-searchable.js +245 -0
- package/lib/select.d.ts +27 -91
- package/lib/select.js +51 -351
- package/lib/styles/common.p.module.css.js +32 -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/types.d.ts +172 -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/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 +19 -0
- package/lib/utils/get-text-from-nodes.d.ts +2 -0
- package/lib/utils/get-text-from-nodes.js +26 -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/item-to-string.d.ts +2 -0
- package/lib/utils/item-to-string.js +7 -0
- package/lib/utils/merge-props.d.ts +19 -0
- package/lib/utils/merge-props.js +104 -0
- package/lib/utils/throttle.d.ts +1 -0
- package/package.json +8 -8
- 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 -15
- package/lib/parts/multiselect.d.ts +0 -86
- package/lib/parts/multiselect.js +0 -455
- package/lib/parts/native-select.d.ts +0 -36
- package/lib/parts/native-select.js +0 -257
- 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/parts/use-backward-compatible-id.d.ts +0 -4
- package/lib/parts/use-backward-compatible-id.js +0 -14
- package/lib/parts/use-observable-force-rerender.d.ts +0 -2
- package/lib/parts/use-observable-force-rerender.js +0 -16
- package/lib/utils.d.ts +0 -22
- package/lib/utils.js +0 -201
- /package/lib/{parts → utils}/throttle.js +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import React from 'react';
|
|
3
2
|
import cn from 'classnames';
|
|
4
3
|
import { useThemeWithUndefined } from '@rescui/ui-contexts';
|
|
5
4
|
import { shouldRenderErrorMessage, ErrorMessage } from '@rescui/form-field';
|
|
6
|
-
import styles from '
|
|
5
|
+
import styles from '../styles/form-trigger.p.module.css.js';
|
|
7
6
|
const SIZE_STYLES = {
|
|
8
7
|
l: styles.sizeL,
|
|
9
8
|
m: styles.sizeM,
|
|
@@ -13,64 +12,47 @@ const THEME_STYLES = {
|
|
|
13
12
|
light: styles.themeLight,
|
|
14
13
|
dark: styles.themeDark
|
|
15
14
|
};
|
|
16
|
-
|
|
17
|
-
const Label = _ref => {
|
|
18
|
-
let {
|
|
19
|
-
children,
|
|
20
|
-
boldLabel
|
|
21
|
-
} = _ref;
|
|
22
|
-
|
|
23
|
-
if (!children) {
|
|
24
|
-
return null;
|
|
25
|
-
} else {
|
|
26
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
27
|
-
className: styles.label,
|
|
28
|
-
"data-rs-internal": boldLabel ? 'select-form-trigger-wrapper__bold-label' : 'select-form-trigger-wrapper__label'
|
|
29
|
-
}, children);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
15
|
const FormTriggerWrapper = /*#__PURE__*/React.forwardRef( // eslint-disable-next-line complexity
|
|
34
|
-
(
|
|
16
|
+
(_ref, ref) => {
|
|
35
17
|
let {
|
|
36
18
|
size,
|
|
37
19
|
theme: themeFromProps,
|
|
38
20
|
className,
|
|
39
|
-
id,
|
|
40
21
|
disabled,
|
|
41
22
|
error,
|
|
42
|
-
errorId,
|
|
43
23
|
reserveErrorLine = false,
|
|
24
|
+
errorMessageProps,
|
|
44
25
|
label,
|
|
26
|
+
labelProps,
|
|
45
27
|
note,
|
|
28
|
+
descriptionProps,
|
|
46
29
|
children,
|
|
47
|
-
onKeyDown,
|
|
48
30
|
boldLabel,
|
|
49
31
|
...restProps
|
|
50
|
-
} =
|
|
32
|
+
} = _ref;
|
|
51
33
|
const theme = useThemeWithUndefined(themeFromProps);
|
|
52
34
|
const hasFooter = Boolean(note) || shouldRenderErrorMessage(error, reserveErrorLine);
|
|
53
35
|
return /*#__PURE__*/React.createElement("div", {
|
|
54
36
|
className: cn(className, styles.main, SIZE_STYLES[size], THEME_STYLES[theme], Boolean(error) && styles.error, disabled && styles.disabled),
|
|
55
|
-
id: id,
|
|
56
37
|
ref: ref,
|
|
57
38
|
"data-test": "select-wrapper",
|
|
58
39
|
"data-rs-internal": 'select-form-trigger-wrapper',
|
|
59
40
|
...restProps
|
|
60
|
-
}, /*#__PURE__*/React.createElement(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
41
|
+
}, label && /*#__PURE__*/React.createElement("div", {
|
|
42
|
+
className: styles.label,
|
|
43
|
+
"data-rs-internal": boldLabel ? 'select-form-trigger-wrapper__bold-label' : 'select-form-trigger-wrapper__label',
|
|
44
|
+
...labelProps
|
|
45
|
+
}, label), children, hasFooter && /*#__PURE__*/React.createElement("div", {
|
|
65
46
|
className: styles.footer
|
|
66
47
|
}, /*#__PURE__*/React.createElement(ErrorMessage, {
|
|
67
|
-
id: errorId,
|
|
68
48
|
className: styles.errorMessage,
|
|
69
|
-
reserveLine: reserveErrorLine
|
|
49
|
+
reserveLine: reserveErrorLine,
|
|
50
|
+
...errorMessageProps
|
|
70
51
|
}, error), note && /*#__PURE__*/React.createElement("div", {
|
|
71
52
|
className: styles.note,
|
|
72
|
-
"data-rs-internal": 'select-form-trigger-wrapper__note'
|
|
53
|
+
"data-rs-internal": 'select-form-trigger-wrapper__note',
|
|
54
|
+
...descriptionProps
|
|
73
55
|
}, note)));
|
|
74
56
|
});
|
|
75
57
|
FormTriggerWrapper.displayName = 'FormTriggerWrapper';
|
|
76
|
-
export { FormTriggerWrapper as default };
|
|
58
|
+
export { FormTriggerWrapper, FormTriggerWrapper as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
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;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from '../styles/common.p.module.css.js';
|
|
3
|
+
|
|
4
|
+
const HiddenSelect = _ref => {
|
|
5
|
+
let {
|
|
6
|
+
name,
|
|
7
|
+
options,
|
|
8
|
+
value,
|
|
9
|
+
isMultiple
|
|
10
|
+
} = _ref;
|
|
11
|
+
const selectProps = {
|
|
12
|
+
name,
|
|
13
|
+
'aria-hidden': true,
|
|
14
|
+
readOnly: true,
|
|
15
|
+
tabIndex: -1
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (isMultiple) {
|
|
19
|
+
selectProps.multiple = true;
|
|
20
|
+
|
|
21
|
+
if (value && value.length !== 0) {
|
|
22
|
+
selectProps.value = value.map(v => String(v.value));
|
|
23
|
+
}
|
|
24
|
+
} else if (value) {
|
|
25
|
+
const singleValue = value;
|
|
26
|
+
selectProps.value = singleValue.value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const arrayValue = isMultiple ? value : [value]; // merge options with value in case the provided value is not included in options
|
|
30
|
+
|
|
31
|
+
const allItems = Array.from( // map will deduplicate options by values
|
|
32
|
+
new Map((!value ? options : [...options, ...arrayValue]).map(item => [item.value, item])).values());
|
|
33
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
34
|
+
className: styles.visuallyHidden
|
|
35
|
+
}, /*#__PURE__*/React.createElement("select", { ...selectProps
|
|
36
|
+
}, /*#__PURE__*/React.createElement("option", {
|
|
37
|
+
value: "",
|
|
38
|
+
label: '\u00A0'
|
|
39
|
+
}, '\u00A0'), allItems.map(option => /*#__PURE__*/React.createElement("option", {
|
|
40
|
+
key: option.value,
|
|
41
|
+
value: option.value
|
|
42
|
+
}, option.label))));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export { HiddenSelect };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
declare type ClearOrLoadingProps = {
|
|
3
|
+
isLoading: boolean;
|
|
4
|
+
canHaveClearIcon: boolean;
|
|
5
|
+
onClearClick: () => void;
|
|
6
|
+
triggerId?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const ClearOrLoading: React.FC<ClearOrLoadingProps>;
|
|
10
|
+
export declare type IconsProps = {
|
|
11
|
+
isLoading?: boolean;
|
|
12
|
+
canHaveClearIcon?: boolean;
|
|
13
|
+
onClear?: () => void;
|
|
14
|
+
triggerId?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const Icons: ({ isLoading, canHaveClearIcon, onClear, triggerId }: IconsProps) => JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import CloseOutlineIcon from '../_virtual/close-outline.js';
|
|
4
|
+
import LoadingOutlineIcon from '../_virtual/loading-outline.js';
|
|
5
|
+
import DownOutlineIcon from '../_virtual/down-outline.js';
|
|
6
|
+
import styles from '../styles/common.p.module.css.js';
|
|
7
|
+
|
|
8
|
+
const ClearOrLoading = _ref => {
|
|
9
|
+
let {
|
|
10
|
+
isLoading,
|
|
11
|
+
canHaveClearIcon,
|
|
12
|
+
onClearClick,
|
|
13
|
+
triggerId,
|
|
14
|
+
className
|
|
15
|
+
} = _ref;
|
|
16
|
+
|
|
17
|
+
if (isLoading) {
|
|
18
|
+
return /*#__PURE__*/React.createElement(LoadingOutlineIcon, {
|
|
19
|
+
style: {
|
|
20
|
+
pointerEvents: 'none'
|
|
21
|
+
},
|
|
22
|
+
className: cn(className, styles.icon),
|
|
23
|
+
"data-test": "loading-icon",
|
|
24
|
+
"data-render-all-sizes": true
|
|
25
|
+
});
|
|
26
|
+
} else if (canHaveClearIcon) {
|
|
27
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
28
|
+
type: "button",
|
|
29
|
+
className: cn(className, styles.icon, styles.clearIcon),
|
|
30
|
+
"data-test": "clear-icon",
|
|
31
|
+
onClick: e => {
|
|
32
|
+
e.stopPropagation();
|
|
33
|
+
onClearClick();
|
|
34
|
+
},
|
|
35
|
+
onPointerDown: e => e.stopPropagation(),
|
|
36
|
+
onMouseDown: e => e.stopPropagation(),
|
|
37
|
+
onKeyDown: e => e.stopPropagation(),
|
|
38
|
+
"aria-label": "Clear",
|
|
39
|
+
"aria-controls": triggerId
|
|
40
|
+
}, /*#__PURE__*/React.createElement(CloseOutlineIcon, {
|
|
41
|
+
"data-render-all-sizes": true
|
|
42
|
+
}));
|
|
43
|
+
} else {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const Icons = _ref2 => {
|
|
49
|
+
let {
|
|
50
|
+
isLoading,
|
|
51
|
+
canHaveClearIcon,
|
|
52
|
+
onClear,
|
|
53
|
+
triggerId
|
|
54
|
+
} = _ref2;
|
|
55
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
56
|
+
className: styles.iconsWrapper
|
|
57
|
+
}, /*#__PURE__*/React.createElement(ClearOrLoading, {
|
|
58
|
+
isLoading: isLoading,
|
|
59
|
+
canHaveClearIcon: canHaveClearIcon,
|
|
60
|
+
onClearClick: onClear,
|
|
61
|
+
triggerId: triggerId
|
|
62
|
+
}), /*#__PURE__*/React.createElement(DownOutlineIcon, {
|
|
63
|
+
className: styles.toggle,
|
|
64
|
+
"data-test": "toggle-icon",
|
|
65
|
+
"data-render-all-sizes": true
|
|
66
|
+
}));
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export { ClearOrLoading, Icons };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { SelectSize, SelectMode, ListBoxItem, ListBoxState } from '../types';
|
|
3
|
+
export declare type ListBoxProps = {
|
|
4
|
+
state: ListBoxState;
|
|
5
|
+
items: ListBoxItem[];
|
|
6
|
+
size?: SelectSize;
|
|
7
|
+
mode?: SelectMode;
|
|
8
|
+
className?: string;
|
|
9
|
+
maxVisibleItems?: number;
|
|
10
|
+
emptyListMessage: string;
|
|
11
|
+
isPrimaryContrast?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare function ListBox({ state, items, size, mode, maxVisibleItems, emptyListMessage, isPrimaryContrast }: ListBoxProps): JSX.Element;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import styles from '../styles/list-box.p.module.css.js';
|
|
4
|
+
import { calculateMaxHeightByItems } from '../utils/calculate-max-height-by-items.js';
|
|
5
|
+
import { getRealItemsCnt } from '../utils/get-real-items-cnt.js';
|
|
6
|
+
import { getTextFromNodes } from '../utils/get-text-from-nodes.js';
|
|
7
|
+
import CheckOutlineIcon from '../_virtual/check-outline.js';
|
|
8
|
+
const SIZE_STYLES = {
|
|
9
|
+
s: styles.sizeS,
|
|
10
|
+
m: styles.sizeM,
|
|
11
|
+
l: styles.sizeL
|
|
12
|
+
};
|
|
13
|
+
const MODE_STYLES = {
|
|
14
|
+
classic: styles.classic,
|
|
15
|
+
rock: styles.rock
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function Option(_ref) {
|
|
19
|
+
let {
|
|
20
|
+
item,
|
|
21
|
+
state
|
|
22
|
+
} = _ref;
|
|
23
|
+
// Get props for the option element
|
|
24
|
+
const ref = useRef(null);
|
|
25
|
+
const {
|
|
26
|
+
selectedMap,
|
|
27
|
+
getItemProps,
|
|
28
|
+
highlightedIndex
|
|
29
|
+
} = state;
|
|
30
|
+
const index = item.index;
|
|
31
|
+
const isSelected = selectedMap.has(item.key);
|
|
32
|
+
const isHighlighted = highlightedIndex === item.index;
|
|
33
|
+
const isDisabled = item.disabled;
|
|
34
|
+
return /*#__PURE__*/React.createElement("li", { ...getItemProps({
|
|
35
|
+
item,
|
|
36
|
+
index,
|
|
37
|
+
'aria-selected': isSelected,
|
|
38
|
+
'tab-index': isHighlighted ? 0 : -1,
|
|
39
|
+
ref
|
|
40
|
+
}),
|
|
41
|
+
className: cn(styles.item, isSelected && styles.selected, isDisabled && styles.disabled),
|
|
42
|
+
"data-rs-internal": "select-list-box__item",
|
|
43
|
+
"data-focused": isHighlighted,
|
|
44
|
+
"data-test": `select-options-list__item_${item.key}`
|
|
45
|
+
}, /*#__PURE__*/React.createElement("span", null, item.label), /*#__PURE__*/React.createElement(CheckOutlineIcon, {
|
|
46
|
+
"data-rs-internal": "select-list-box__check-icon",
|
|
47
|
+
className: cn(styles.checkIcon, isSelected && styles.visible)
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function ListBoxGroup(_ref2) {
|
|
52
|
+
let {
|
|
53
|
+
item,
|
|
54
|
+
isFirst,
|
|
55
|
+
state
|
|
56
|
+
} = _ref2;
|
|
57
|
+
const hasHeading = item.label !== null && item.label !== undefined;
|
|
58
|
+
const hasDivider = !isFirst && !hasHeading; // If the section is not the first, add a divider for visual separation
|
|
59
|
+
|
|
60
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, hasDivider && /*#__PURE__*/React.createElement("hr", {
|
|
61
|
+
className: styles.divider
|
|
62
|
+
}), /*#__PURE__*/React.createElement("li", {
|
|
63
|
+
role: "presentation"
|
|
64
|
+
}, hasHeading && /*#__PURE__*/React.createElement("span", {
|
|
65
|
+
className: styles.groupHeader,
|
|
66
|
+
role: "presentation",
|
|
67
|
+
"data-rs-internal": "select-list-box__group-header"
|
|
68
|
+
}, item.label), /*#__PURE__*/React.createElement("ul", {
|
|
69
|
+
role: "group",
|
|
70
|
+
"aria-label": hasHeading ? getTextFromNodes(item.label) : undefined,
|
|
71
|
+
style: {
|
|
72
|
+
padding: 0,
|
|
73
|
+
listStyle: 'none'
|
|
74
|
+
}
|
|
75
|
+
}, item.options.map(option => /*#__PURE__*/React.createElement(Option, {
|
|
76
|
+
key: option.key,
|
|
77
|
+
item: option,
|
|
78
|
+
state: state
|
|
79
|
+
})))));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function ListBox(_ref3) {
|
|
83
|
+
let {
|
|
84
|
+
state,
|
|
85
|
+
items,
|
|
86
|
+
size,
|
|
87
|
+
mode,
|
|
88
|
+
maxVisibleItems = 5,
|
|
89
|
+
emptyListMessage,
|
|
90
|
+
isPrimaryContrast = false
|
|
91
|
+
} = _ref3;
|
|
92
|
+
const {
|
|
93
|
+
menuProps
|
|
94
|
+
} = state;
|
|
95
|
+
const firstGroupKey = items.find(item => item.type === 'group')?.key;
|
|
96
|
+
const itemsCount = getRealItemsCnt(items);
|
|
97
|
+
return /*#__PURE__*/React.createElement("ul", { ...menuProps,
|
|
98
|
+
className: cn(styles.listBox, SIZE_STYLES[size], MODE_STYLES[mode]),
|
|
99
|
+
style: {
|
|
100
|
+
'--_rs-select-list-box-max-height-by-items': calculateMaxHeightByItems(itemsCount, maxVisibleItems),
|
|
101
|
+
'--rs-select-contrast-primary': isPrimaryContrast ? '1' : '0'
|
|
102
|
+
},
|
|
103
|
+
"data-rs-internal": "select-list-box",
|
|
104
|
+
"data-test": "select-options-list"
|
|
105
|
+
}, itemsCount === 0 ? /*#__PURE__*/React.createElement("li", {
|
|
106
|
+
className: cn(styles.item, styles.disabled),
|
|
107
|
+
"data-rs-internal": "select-list-box__item"
|
|
108
|
+
}, /*#__PURE__*/React.createElement("span", null, emptyListMessage)) : items.map(item => item.type === 'group' ? /*#__PURE__*/React.createElement(ListBoxGroup, {
|
|
109
|
+
key: item.key,
|
|
110
|
+
item: item,
|
|
111
|
+
state: state,
|
|
112
|
+
isFirst: item.key === firstGroupKey
|
|
113
|
+
}) : /*#__PURE__*/React.createElement(Option, {
|
|
114
|
+
key: item.key,
|
|
115
|
+
item: item,
|
|
116
|
+
state: state
|
|
117
|
+
})));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { ListBox };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SelectOption } from '../types';
|
|
3
|
+
export interface MultiTriggerProps {
|
|
4
|
+
selectedItems: SelectOption[];
|
|
5
|
+
removeSelectedItem: (item: SelectOption) => void;
|
|
6
|
+
valueProps: object;
|
|
7
|
+
isSingleLine: boolean;
|
|
8
|
+
isDisabled: boolean;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
triggerRef?: React.RefObject<HTMLDivElement>;
|
|
11
|
+
}
|
|
12
|
+
export declare function MultiTrigger({ selectedItems, valueProps, isSingleLine, isDisabled, placeholder, triggerRef, removeSelectedItem }: MultiTriggerProps): JSX.Element;
|
|
@@ -0,0 +1,70 @@
|
|
|
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 { getOptionValue } from '../utils/get-option-value.js';
|
|
7
|
+
import Foldable from './foldable.js';
|
|
8
|
+
|
|
9
|
+
function MultiTrigger(_ref) {
|
|
10
|
+
let {
|
|
11
|
+
selectedItems,
|
|
12
|
+
valueProps,
|
|
13
|
+
isSingleLine,
|
|
14
|
+
isDisabled,
|
|
15
|
+
placeholder,
|
|
16
|
+
triggerRef,
|
|
17
|
+
removeSelectedItem
|
|
18
|
+
} = _ref;
|
|
19
|
+
const hasValue = selectedItems.length > 0;
|
|
20
|
+
|
|
21
|
+
if (!hasValue) {
|
|
22
|
+
return /*#__PURE__*/React.createElement("div", { ...valueProps,
|
|
23
|
+
className: cn(styles.triggerText, styles.labelNotSelected),
|
|
24
|
+
"data-test": 'multiselect__trigger_content'
|
|
25
|
+
}, placeholder);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tags = selectedItems.map(option => {
|
|
29
|
+
const key = getOptionValue(option);
|
|
30
|
+
return /*#__PURE__*/React.createElement(RemovableTag, {
|
|
31
|
+
key: key,
|
|
32
|
+
tabIndex: -1,
|
|
33
|
+
"data-test": `selected-tag-${key}`,
|
|
34
|
+
className: styles.tag,
|
|
35
|
+
disabled: isDisabled,
|
|
36
|
+
onRemoveClick: () => {
|
|
37
|
+
removeSelectedItem(option);
|
|
38
|
+
triggerRef.current?.focus({
|
|
39
|
+
focusVisible: false
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
"data-rs-internal": "select-trigger__removable-tag",
|
|
43
|
+
wrap: !isSingleLine,
|
|
44
|
+
"aria-label": getTextFromNodes(option.label),
|
|
45
|
+
onFocus: e => {
|
|
46
|
+
if (e.target.getAttribute('tabindex') === '-1') {
|
|
47
|
+
triggerRef.current?.focus({
|
|
48
|
+
focusVisible: false
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}, option.label);
|
|
53
|
+
});
|
|
54
|
+
return /*#__PURE__*/React.createElement("div", { ...valueProps,
|
|
55
|
+
className: styles.multi,
|
|
56
|
+
"data-test": "multiselect__trigger_content"
|
|
57
|
+
}, isSingleLine ? /*#__PURE__*/React.createElement(Foldable, {
|
|
58
|
+
className: styles.tagsContainer,
|
|
59
|
+
renderHiddenCounter: (n, ref) => /*#__PURE__*/React.createElement(Tag, {
|
|
60
|
+
className: cn(styles.tag, styles.filledTag),
|
|
61
|
+
key: "+",
|
|
62
|
+
ref: ref,
|
|
63
|
+
"data-rs-internal": "select-trigger__tag"
|
|
64
|
+
}, "+", n)
|
|
65
|
+
}, tags) : /*#__PURE__*/React.createElement("div", {
|
|
66
|
+
className: styles.tagsContainer
|
|
67
|
+
}, tags));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
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,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Theme } from '@rescui/ui-contexts';
|
|
3
|
+
import type { DropdownProps, DropdownImperativeHandle } from '@rescui/dropdown';
|
|
4
|
+
import type { SelectMode, SelectSize, ListBoxState, ListBoxItem, Placement } from '../types';
|
|
5
|
+
export declare type PopupContentProps = {
|
|
6
|
+
theme: Theme;
|
|
7
|
+
listBoxState: ListBoxState;
|
|
8
|
+
triggerRef: React.RefObject<HTMLElement>;
|
|
9
|
+
dropdownRef?: React.RefObject<DropdownImperativeHandle>;
|
|
10
|
+
listBoxItems?: ListBoxItem[];
|
|
11
|
+
placement: Placement;
|
|
12
|
+
size?: SelectSize;
|
|
13
|
+
mode?: SelectMode;
|
|
14
|
+
emptyListMessage: string;
|
|
15
|
+
maxVisibleItems?: number;
|
|
16
|
+
trigger?: DropdownProps['trigger'];
|
|
17
|
+
isOpen?: boolean;
|
|
18
|
+
dropdownUpdateDeps?: unknown[];
|
|
19
|
+
};
|
|
20
|
+
export declare const PopupContent: ({ theme, listBoxState, triggerRef, dropdownRef, listBoxItems, placement, size: sizeFromProps, mode, emptyListMessage, maxVisibleItems, trigger, isOpen, dropdownUpdateDeps }: PopupContentProps) => JSX.Element;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { Dropdown } from '@rescui/dropdown';
|
|
3
|
+
import { useActualSizeFromCss } from '../hooks/use-actual-size-from-css.js';
|
|
4
|
+
import { usePrimaryContrastCssVarTransfer } from '../hooks/use-primary-contrast-css-var-transfer.js';
|
|
5
|
+
import styles from '../styles/common.p.module.css.js';
|
|
6
|
+
import { ListBox } from './list-box.js'; // eslint-disable-next-line complexity
|
|
7
|
+
|
|
8
|
+
const PopupContent = _ref => {
|
|
9
|
+
let {
|
|
10
|
+
theme,
|
|
11
|
+
listBoxState,
|
|
12
|
+
triggerRef,
|
|
13
|
+
dropdownRef,
|
|
14
|
+
listBoxItems,
|
|
15
|
+
placement,
|
|
16
|
+
size: sizeFromProps,
|
|
17
|
+
mode,
|
|
18
|
+
emptyListMessage,
|
|
19
|
+
maxVisibleItems,
|
|
20
|
+
trigger,
|
|
21
|
+
isOpen,
|
|
22
|
+
dropdownUpdateDeps = []
|
|
23
|
+
} = _ref;
|
|
24
|
+
const {
|
|
25
|
+
size,
|
|
26
|
+
observableRef
|
|
27
|
+
} = useActualSizeFromCss({
|
|
28
|
+
sizeFromProps,
|
|
29
|
+
triggerRef
|
|
30
|
+
});
|
|
31
|
+
const {
|
|
32
|
+
isPrimaryContrast
|
|
33
|
+
} = usePrimaryContrastCssVarTransfer({
|
|
34
|
+
isOpen,
|
|
35
|
+
triggerRef
|
|
36
|
+
});
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (dropdownRef.current) {
|
|
39
|
+
dropdownRef.current.scheduleUpdate();
|
|
40
|
+
} // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41
|
+
|
|
42
|
+
}, [listBoxItems, size, ...dropdownUpdateDeps]);
|
|
43
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
44
|
+
ref: observableRef,
|
|
45
|
+
className: styles.observable
|
|
46
|
+
}), /*#__PURE__*/React.createElement(Dropdown, {
|
|
47
|
+
theme: theme,
|
|
48
|
+
ref: dropdownRef,
|
|
49
|
+
placement: placement,
|
|
50
|
+
maxWidth: "trigger",
|
|
51
|
+
minWidth: "trigger",
|
|
52
|
+
leastMaxHeight: 999999,
|
|
53
|
+
isOpen: isOpen,
|
|
54
|
+
cancelCloseAnimation: true,
|
|
55
|
+
disableFocusLock: true,
|
|
56
|
+
trigger: trigger
|
|
57
|
+
}, /*#__PURE__*/React.createElement(ListBox, {
|
|
58
|
+
state: listBoxState,
|
|
59
|
+
size: size,
|
|
60
|
+
mode: mode,
|
|
61
|
+
maxVisibleItems: maxVisibleItems,
|
|
62
|
+
emptyListMessage: emptyListMessage,
|
|
63
|
+
items: listBoxItems,
|
|
64
|
+
isPrimaryContrast: isPrimaryContrast
|
|
65
|
+
})));
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { PopupContent };
|