@rc-component/select 1.6.14 → 1.7.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/README.md CHANGED
@@ -83,7 +83,7 @@ export default () => (
83
83
  | dropdownAlign | additional align applied to dropdown | [AlignType](https://github.com/react-component/trigger/blob/728d7e92394aa4b3214650f743fc47e1382dfa68/src/interface.ts#L25-L80) | {} |
84
84
  | dropdownMenuStyle | additional style applied to dropdown menu | Object | React.CSSProperties |
85
85
  | notFoundContent | specify content to show when no result matches. | ReactNode | 'Not Found' |
86
- | tokenSeparators | separator used to tokenize on tag/multiple mode | string[]? | |
86
+ | tokenSeparators | separator used to tokenize on tag/multiple mode | `string[] \| ((input: string) => string[])` | |
87
87
  | open | control select open | boolean | |
88
88
  | defaultOpen | control select default open | boolean | |
89
89
  | placeholder | select placeholder | React Node | |
@@ -90,7 +90,7 @@ export interface BaseSelectProps extends BaseSelectPrivateProps, React.AriaAttri
90
90
  maxTagTextLength?: number;
91
91
  maxTagCount?: number | 'responsive';
92
92
  maxTagPlaceholder?: React.ReactNode | ((omittedValues: DisplayValueType[]) => React.ReactNode);
93
- tokenSeparators?: string[];
93
+ tokenSeparators?: string[] | ((input: string) => string[]);
94
94
  allowClear?: boolean | {
95
95
  clearIcon?: React.ReactNode;
96
96
  };
@@ -138,7 +138,20 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
138
138
  const [rawOpen, mergedOpen, triggerOpen, lockOptions] = useOpen(defaultOpen || false, open, onPopupVisibleChange, nextOpen => disabled || emptyListContent ? false : nextOpen);
139
139
 
140
140
  // ============================= Search =============================
141
- const tokenWithEnter = React.useMemo(() => (tokenSeparators || []).some(tokenSeparator => ['\n', '\r\n'].includes(tokenSeparator)), [tokenSeparators]);
141
+ const tokenWithEnter = React.useMemo(() => typeof tokenSeparators === 'function' || (tokenSeparators || []).some(tokenSeparator => ['\n', '\r\n'].includes(tokenSeparator)), [tokenSeparators]);
142
+ const splitByTokenSeparators = React.useMemo(() => {
143
+ if (typeof tokenSeparators === 'function') {
144
+ return (input, end) => {
145
+ const tokens = tokenSeparators(input);
146
+ const isUnchanged = Array.isArray(tokens) && tokens.length === 1 && tokens[0] === input;
147
+ if (!Array.isArray(tokens) || !tokens.length || isUnchanged) {
148
+ return null;
149
+ }
150
+ return typeof end !== 'undefined' ? tokens.slice(0, end) : tokens;
151
+ };
152
+ }
153
+ return (input, end) => getSeparatedContent(input, tokenSeparators, end);
154
+ }, [tokenSeparators]);
142
155
  const onInternalSearch = (searchText, fromTyping, isCompositing) => {
143
156
  if (multiple && isValidCount(maxCount) && displayValues.length >= maxCount) {
144
157
  return;
@@ -146,10 +159,8 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
146
159
  let ret = true;
147
160
  let newSearchText = searchText;
148
161
  onActiveValueChange?.(null);
149
- const separatedList = getSeparatedContent(searchText, tokenSeparators, isValidCount(maxCount) ? maxCount - displayValues.length : undefined);
150
-
151
- // Check if match the `tokenSeparators`
152
- const patchLabels = isCompositing ? null : separatedList;
162
+ const cap = isValidCount(maxCount) ? maxCount - displayValues.length : undefined;
163
+ const patchLabels = isCompositing ? null : splitByTokenSeparators(searchText, cap);
153
164
 
154
165
  // Ignore combobox since it's not split-able
155
166
  if (mode !== 'combobox' && patchLabels) {
@@ -87,7 +87,7 @@ const Input = /*#__PURE__*/React.forwardRef((props, ref) => {
87
87
  } = event.currentTarget;
88
88
 
89
89
  // Handle Enter key submission - referencing Selector implementation
90
- if (key === 'Enter' && mode === 'tags' && !compositionStatusRef.current && onSearchSubmit) {
90
+ if (key === 'Enter' && mode === 'tags' && !open && !compositionStatusRef.current && onSearchSubmit) {
91
91
  onSearchSubmit(nextVal);
92
92
  }
93
93
 
@@ -27,7 +27,7 @@ export interface SelectInputProps extends Omit<React.HTMLAttributes<HTMLDivEleme
27
27
  onSelectorRemove?: (value: DisplayValueType) => void;
28
28
  maxLength?: number;
29
29
  autoFocus?: boolean;
30
- /** Check if `tokenSeparators` contains `\n` or `\r\n` */
30
+ /** Check if tokenization should treat pasted line breaks as separators */
31
31
  tokenWithEnter?: boolean;
32
32
  className?: string;
33
33
  style?: React.CSSProperties;
@@ -90,7 +90,7 @@ export interface BaseSelectProps extends BaseSelectPrivateProps, React.AriaAttri
90
90
  maxTagTextLength?: number;
91
91
  maxTagCount?: number | 'responsive';
92
92
  maxTagPlaceholder?: React.ReactNode | ((omittedValues: DisplayValueType[]) => React.ReactNode);
93
- tokenSeparators?: string[];
93
+ tokenSeparators?: string[] | ((input: string) => string[]);
94
94
  allowClear?: boolean | {
95
95
  clearIcon?: React.ReactNode;
96
96
  };
@@ -147,7 +147,20 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
147
147
  const [rawOpen, mergedOpen, triggerOpen, lockOptions] = (0, _useOpen.default)(defaultOpen || false, open, onPopupVisibleChange, nextOpen => disabled || emptyListContent ? false : nextOpen);
148
148
 
149
149
  // ============================= Search =============================
150
- const tokenWithEnter = React.useMemo(() => (tokenSeparators || []).some(tokenSeparator => ['\n', '\r\n'].includes(tokenSeparator)), [tokenSeparators]);
150
+ const tokenWithEnter = React.useMemo(() => typeof tokenSeparators === 'function' || (tokenSeparators || []).some(tokenSeparator => ['\n', '\r\n'].includes(tokenSeparator)), [tokenSeparators]);
151
+ const splitByTokenSeparators = React.useMemo(() => {
152
+ if (typeof tokenSeparators === 'function') {
153
+ return (input, end) => {
154
+ const tokens = tokenSeparators(input);
155
+ const isUnchanged = Array.isArray(tokens) && tokens.length === 1 && tokens[0] === input;
156
+ if (!Array.isArray(tokens) || !tokens.length || isUnchanged) {
157
+ return null;
158
+ }
159
+ return typeof end !== 'undefined' ? tokens.slice(0, end) : tokens;
160
+ };
161
+ }
162
+ return (input, end) => (0, _valueUtil.getSeparatedContent)(input, tokenSeparators, end);
163
+ }, [tokenSeparators]);
151
164
  const onInternalSearch = (searchText, fromTyping, isCompositing) => {
152
165
  if (multiple && (0, _valueUtil.isValidCount)(maxCount) && displayValues.length >= maxCount) {
153
166
  return;
@@ -155,10 +168,8 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
155
168
  let ret = true;
156
169
  let newSearchText = searchText;
157
170
  onActiveValueChange?.(null);
158
- const separatedList = (0, _valueUtil.getSeparatedContent)(searchText, tokenSeparators, (0, _valueUtil.isValidCount)(maxCount) ? maxCount - displayValues.length : undefined);
159
-
160
- // Check if match the `tokenSeparators`
161
- const patchLabels = isCompositing ? null : separatedList;
171
+ const cap = (0, _valueUtil.isValidCount)(maxCount) ? maxCount - displayValues.length : undefined;
172
+ const patchLabels = isCompositing ? null : splitByTokenSeparators(searchText, cap);
162
173
 
163
174
  // Ignore combobox since it's not split-able
164
175
  if (mode !== 'combobox' && patchLabels) {
@@ -96,7 +96,7 @@ const Input = /*#__PURE__*/React.forwardRef((props, ref) => {
96
96
  } = event.currentTarget;
97
97
 
98
98
  // Handle Enter key submission - referencing Selector implementation
99
- if (key === 'Enter' && mode === 'tags' && !compositionStatusRef.current && onSearchSubmit) {
99
+ if (key === 'Enter' && mode === 'tags' && !open && !compositionStatusRef.current && onSearchSubmit) {
100
100
  onSearchSubmit(nextVal);
101
101
  }
102
102
 
@@ -27,7 +27,7 @@ export interface SelectInputProps extends Omit<React.HTMLAttributes<HTMLDivEleme
27
27
  onSelectorRemove?: (value: DisplayValueType) => void;
28
28
  maxLength?: number;
29
29
  autoFocus?: boolean;
30
- /** Check if `tokenSeparators` contains `\n` or `\r\n` */
30
+ /** Check if tokenization should treat pasted line breaks as separators */
31
31
  tokenWithEnter?: boolean;
32
32
  className?: string;
33
33
  style?: React.CSSProperties;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rc-component/select",
3
- "version": "1.6.14",
3
+ "version": "1.7.0",
4
4
  "description": "React Select",
5
5
  "engines": {
6
6
  "node": ">=8.x"