@zohodesk/components 1.4.7 → 1.4.9

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 (47) hide show
  1. package/.cli/propValidation_report.html +1 -1
  2. package/README.md +17 -4
  3. package/es/Accordion/Accordion.js +1 -1
  4. package/es/Card/Card.js +1 -1
  5. package/es/MultiSelect/AdvancedGroupMultiSelect.js +16 -8
  6. package/es/MultiSelect/AdvancedMultiSelect.js +13 -6
  7. package/es/MultiSelect/EmptyState.js +2 -1
  8. package/es/MultiSelect/MultiSelect.js +27 -16
  9. package/es/MultiSelect/MultiSelectWithAvatar.js +9 -2
  10. package/es/MultiSelect/SelectedOptions.js +4 -2
  11. package/es/MultiSelect/Suggestions.js +10 -2
  12. package/es/MultiSelect/__tests__/MultiSelect.spec.js +25 -0
  13. package/es/MultiSelect/__tests__/Suggestions.spec.js +58 -0
  14. package/es/MultiSelect/__tests__/__snapshots__/MultiSelect.spec.js.snap +253 -0
  15. package/es/MultiSelect/__tests__/__snapshots__/Suggestions.spec.js.snap +343 -0
  16. package/es/MultiSelect/constants.js +6 -0
  17. package/es/MultiSelect/props/propTypes.js +15 -55
  18. package/es/Popup/Popup.js +45 -17
  19. package/es/Popup/Registry.js +1 -0
  20. package/es/Select/Select.js +1 -1
  21. package/es/Select/__tests__/Select.spec.js +8 -1
  22. package/es/utils/dropDownUtils.js +25 -6
  23. package/es/v1/Popup/Popup.js +1 -1
  24. package/es/v1/Select/Select.js +1 -1
  25. package/lib/Accordion/Accordion.js +2 -2
  26. package/lib/Card/Card.js +2 -2
  27. package/lib/MultiSelect/AdvancedGroupMultiSelect.js +94 -83
  28. package/lib/MultiSelect/AdvancedMultiSelect.js +16 -7
  29. package/lib/MultiSelect/EmptyState.js +3 -1
  30. package/lib/MultiSelect/MultiSelect.js +30 -17
  31. package/lib/MultiSelect/MultiSelectWithAvatar.js +11 -3
  32. package/lib/MultiSelect/SelectedOptions.js +4 -2
  33. package/lib/MultiSelect/Suggestions.js +10 -2
  34. package/lib/MultiSelect/__tests__/MultiSelect.spec.js +25 -0
  35. package/lib/MultiSelect/__tests__/Suggestions.spec.js +58 -0
  36. package/lib/MultiSelect/__tests__/__snapshots__/MultiSelect.spec.js.snap +253 -0
  37. package/lib/MultiSelect/__tests__/__snapshots__/Suggestions.spec.js.snap +343 -0
  38. package/lib/MultiSelect/constants.js +13 -0
  39. package/lib/MultiSelect/props/propTypes.js +14 -55
  40. package/lib/Popup/Popup.js +54 -18
  41. package/lib/Popup/Registry.js +1 -0
  42. package/lib/Select/Select.js +2 -2
  43. package/lib/Select/__tests__/Select.spec.js +8 -1
  44. package/lib/utils/dropDownUtils.js +24 -3
  45. package/lib/v1/Popup/Popup.js +2 -2
  46. package/lib/v1/Select/Select.js +2 -2
  47. package/package.json +11 -9
package/README.md CHANGED
@@ -2,15 +2,28 @@
2
2
 
3
3
  Dot UI is a customizable React component library built to deliver a clean, accessible, and developer-friendly UI experience. It offers a growing set of reusable components designed to align with modern design systems and streamline application development across projects.
4
4
 
5
+ # 1.4.9
6
+
7
+ - **MultiSelect , MultiSelectWithAvatar, AdvancedMultiSelect, AdvancedGroupMultiSelect**
8
+ - `limit` prop supported
9
+ - `limitReachedMessage` prop supported in i18nKeys
10
+
11
+ # 1.4.8
12
+
13
+ - Added UNSAFE_ prefix to deprecated lifecycle methods: componentWillMount, componentWillReceiveProps, and componentWillUpdate.
14
+
15
+ - **Popup**
16
+ - Handled potential memory leaks by `event listeners`.
17
+ - Added unmount handling for `requestAnimationFrame` to ensure proper cleanup.
18
+
19
+
5
20
  # 1.4.7
6
21
 
7
- - **Card**
8
- - Added support for reverse infinite scroll with `isRecentOnBottom`.
22
+ - **Card** - Added support for reverse infinite scroll with `isRecentOnBottom`.
9
23
 
10
24
  # 1.4.6
11
25
 
12
- - **Popup**
13
- - - Added fixed popup scroll block behavior support to iframe elements (same-origin only).
26
+ - **Popup** - Added fixed popup scroll block behavior support to iframe elements (same-origin only).
14
27
 
15
28
  # 1.4.5
16
29
 
@@ -25,7 +25,7 @@ export default class Accordion extends React.Component {
25
25
  });
26
26
  }
27
27
 
28
- componentWillReceiveProps(nextProps) {
28
+ UNSAFE_componentWillReceiveProps(nextProps) {
29
29
  if (this.props.selectedItem !== nextProps.selectedItem && !this.props.disableInternalState) {
30
30
  this.setState({
31
31
  selectedItem: nextProps.selectedItem
package/es/Card/Card.js CHANGED
@@ -102,7 +102,7 @@ export default class Card extends Component {
102
102
  //this.onClearScroll = debounce(this.setScroll.bind(this, false), 500);
103
103
  }
104
104
 
105
- componentWillReceiveProps(nextProps) {
105
+ UNSAFE_componentWillReceiveProps(nextProps) {
106
106
  if (this.from !== nextProps.from) {
107
107
  this.from = nextProps.from;
108
108
  }
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { AdvancedGroupMultiSelect_propTypes } from "./props/propTypes";
3
3
  import { AdvancedGroupMultiSelect_defaultProps } from "./props/defaultProps";
4
+ import { MULTISELECT_I18N_KEYS } from "./constants";
4
5
  /**** Components ****/
5
6
 
6
7
  import Loader from '@zohodesk/svg/lib/Loader/Loader';
@@ -185,7 +186,8 @@ class AdvancedGroupMultiSelect extends React.Component {
185
186
 
186
187
  handleSelectedOptionIdChange(selectedGroupOptions, normalizedFormatOptions, normalizedSelectedOptions) {
187
188
  const {
188
- allowValueFallback
189
+ allowValueFallback,
190
+ limit
189
191
  } = this.props;
190
192
  let newSelectedOptions = selectedGroupOptions.map(option => optionIdGrouping(option.id, option.groupId));
191
193
  let selectedOptionsLength = newSelectedOptions.length;
@@ -197,7 +199,8 @@ class AdvancedGroupMultiSelect extends React.Component {
197
199
  selectedOptions: newSelectedOptions,
198
200
  normalizedFormatOptions: formatOptions,
199
201
  selectedOptionsLength,
200
- allowValueFallback
202
+ allowValueFallback,
203
+ limit
201
204
  });
202
205
  }
203
206
 
@@ -390,7 +393,8 @@ class AdvancedGroupMultiSelect extends React.Component {
390
393
  getNextOptions,
391
394
  isPopupOpen,
392
395
  isPopupOpenOnEnter,
393
- onKeyDown
396
+ onKeyDown,
397
+ limit
394
398
  } = this.props;
395
399
  let highLightedSelectOptionsLen = highLightedSelectOptions.length;
396
400
 
@@ -442,7 +446,7 @@ class AdvancedGroupMultiSelect extends React.Component {
442
446
  hoverIndex: hoverIndex + 1
443
447
  });
444
448
  }
445
- } else if (keyCode === 13) {
449
+ } else if (keyCode === 13 && selectedOptions.length < limit) {
446
450
  //enter key
447
451
  let id = suggestions[hoverIndex] || {};
448
452
  isPopupOpen && !getIsEmptyValue(id) && this.handleSelectOption(id, null, null, e);
@@ -884,13 +888,15 @@ class AdvancedGroupMultiSelect extends React.Component {
884
888
  needEffect,
885
889
  autoComplete,
886
890
  getTargetRef,
887
- isFocus
891
+ isFocus,
892
+ limit
888
893
  } = this.props;
889
894
  let {
890
- clearText = 'Clear all'
895
+ clearText = MULTISELECT_I18N_KEYS.clearText,
896
+ limitReachedMessage = MULTISELECT_I18N_KEYS.limitReachedMessage
891
897
  } = i18nKeys;
892
898
  let {
893
- clearLabel = 'Clear all'
899
+ clearLabel = MULTISELECT_I18N_KEYS.clearText
894
900
  } = a11y;
895
901
  i18nKeys = Object.assign({}, i18nKeys, {
896
902
  emptyText: i18nKeys.emptyText || emptyMessage,
@@ -1026,7 +1032,7 @@ class AdvancedGroupMultiSelect extends React.Component {
1026
1032
  }, /*#__PURE__*/React.createElement(Card, {
1027
1033
  customClass: `${style.box} ${style[`${palette}Box`]}`,
1028
1034
  onScroll: this.handleScroll
1029
- }, needSelectAll ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
1035
+ }, needSelectAll && !(limit >= 0) ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
1030
1036
  onSelect: this.handleSelectAll,
1031
1037
  selectAllText: selectAllText,
1032
1038
  suggestions: suggestionOptionIds,
@@ -1065,6 +1071,8 @@ class AdvancedGroupMultiSelect extends React.Component {
1065
1071
  a11y: {
1066
1072
  role: 'option'
1067
1073
  },
1074
+ limit: limit,
1075
+ limitReachedMessage: limitReachedMessage,
1068
1076
  dataId: `${dataId}_Options`
1069
1077
  }));
1070
1078
  }) : /*#__PURE__*/React.createElement(EmptyState, {
@@ -2,6 +2,7 @@
2
2
  import React from 'react';
3
3
  import { AdvancedMultiSelect_propTypes } from "./props/propTypes";
4
4
  import { AdvancedMultiSelect_defaultProps } from "./props/defaultProps";
5
+ import { MULTISELECT_I18N_KEYS } from "./constants";
5
6
  /**** Components ****/
6
7
 
7
8
  import { MultiSelectComponent } from "./MultiSelect";
@@ -177,7 +178,8 @@ export class AdvancedMultiSelectComponent extends MultiSelectComponent {
177
178
  const {
178
179
  selectedOptionsLimit,
179
180
  selectedOptionDetails,
180
- allowValueFallback
181
+ allowValueFallback,
182
+ limit
181
183
  } = props;
182
184
  showedSelectedOptionsCount = getIsEmptyValue(showedSelectedOptionsCount) ? selectedOptionsLimit : showedSelectedOptionsCount;
183
185
  const {
@@ -191,7 +193,8 @@ export class AdvancedMultiSelectComponent extends MultiSelectComponent {
191
193
  selectedOptions,
192
194
  normalizedFormatOptions: formatOptions,
193
195
  selectedOptionsLength: showedSelectedOptionsCount,
194
- allowValueFallback: allowValueFallback
196
+ allowValueFallback,
197
+ limit
195
198
  });
196
199
  }
197
200
 
@@ -385,7 +388,8 @@ export class AdvancedMultiSelectComponent extends MultiSelectComponent {
385
388
  positionsOffset,
386
389
  targetOffset,
387
390
  isRestrictScroll,
388
- isFocus
391
+ isFocus,
392
+ limit
389
393
  } = this.props;
390
394
  let {
391
395
  SuggestionsProps = {},
@@ -395,10 +399,11 @@ export class AdvancedMultiSelectComponent extends MultiSelectComponent {
395
399
  containerClass = ''
396
400
  } = customClass;
397
401
  const {
398
- clearText = 'Clear all'
402
+ clearText = MULTISELECT_I18N_KEYS.clearText,
403
+ limitReachedMessage = MULTISELECT_I18N_KEYS.limitReachedMessage
399
404
  } = i18nKeys;
400
405
  const {
401
- clearLabel = 'Clear all'
406
+ clearLabel = MULTISELECT_I18N_KEYS.clearText
402
407
  } = a11y;
403
408
  i18nKeys = Object.assign({}, i18nKeys, {
404
409
  emptyText: i18nKeys.emptyText || emptyMessage,
@@ -541,7 +546,7 @@ export class AdvancedMultiSelectComponent extends MultiSelectComponent {
541
546
  }, /*#__PURE__*/React.createElement(Card, {
542
547
  customClass: style.box,
543
548
  onScroll: this.handleScroll
544
- }, needSelectAll ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
549
+ }, needSelectAll && !(limit >= 0) ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
545
550
  onSelect: this.handleSelectAll,
546
551
  selectAllText: selectAllText,
547
552
  suggestions: suggestions,
@@ -563,6 +568,8 @@ export class AdvancedMultiSelectComponent extends MultiSelectComponent {
563
568
  role: 'option'
564
569
  },
565
570
  dataId: `${dataIdMultiSelectComp}_Options`,
571
+ limit: limit,
572
+ limitReachedMessage: limitReachedMessage,
566
573
  ...SuggestionsProps
567
574
  }) : /*#__PURE__*/React.createElement(EmptyState, {
568
575
  isLoading: isFetchingOptions,
@@ -2,6 +2,7 @@
2
2
  import React from 'react';
3
3
  import { EmptyState_propTypes } from "./props/propTypes";
4
4
  import { EmptyState_defaultProps } from "./props/defaultProps";
5
+ import { MULTISELECT_I18N_KEYS } from "./constants";
5
6
  /**** CSS ****/
6
7
 
7
8
  import style from "./MultiSelect.module.css";
@@ -23,7 +24,7 @@ export default class EmptyState extends React.PureComponent {
23
24
  a11y
24
25
  } = this.props;
25
26
  let {
26
- loadingText = 'Loading',
27
+ loadingText = MULTISELECT_I18N_KEYS.loadingText,
27
28
  emptyText = emptyMessage,
28
29
  noMoreText = noMoreOptionsMessage,
29
30
  searchEmptyText = searchEmptyMessage
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import { MultiSelect_propTypes } from "./props/propTypes";
4
4
  import { MultiSelect_defaultProps } from "./props/defaultProps";
5
5
  import { defaultProps as MobileHeader_defaultProps } from "./MobileHeader/props/defaultProps";
6
+ import { MULTISELECT_I18N_KEYS } from "./constants";
6
7
  /**** Components ****/
7
8
 
8
9
  import Popup from "../Popup/Popup";
@@ -89,7 +90,7 @@ export class MultiSelectComponent extends React.Component {
89
90
  // suggestionContainer.addEventListener('scroll', this.handleScroll);
90
91
  }
91
92
 
92
- componentWillReceiveProps(nextProps) {
93
+ UNSAFE_componentWillReceiveProps(nextProps) {
93
94
  const {
94
95
  selectedOptions,
95
96
  options,
@@ -234,12 +235,14 @@ export class MultiSelectComponent extends React.Component {
234
235
 
235
236
  handleGetSelectedOptions(selectedOptions, normalizedFormatOptions, props) {
236
237
  const {
237
- allowValueFallback
238
+ allowValueFallback,
239
+ limit
238
240
  } = props;
239
241
  return this.getSelectedOptions({
240
242
  selectedOptions,
241
243
  normalizedFormatOptions,
242
- allowValueFallback
244
+ allowValueFallback,
245
+ limit
243
246
  });
244
247
  }
245
248
 
@@ -313,8 +316,10 @@ export class MultiSelectComponent extends React.Component {
313
316
  getNextOptions,
314
317
  isPopupOpen,
315
318
  isPopupOpenOnEnter,
316
- onKeyDown
319
+ onKeyDown,
320
+ limit
317
321
  } = this.props;
322
+ const allowKeyboardActions = !limit || limit && selectedOptions.length < limit;
318
323
  const highLightedSelectOptionsLen = highLightedSelectOptions.length;
319
324
 
320
325
  if (isPopupOpen && (keyCode === 38 || keyCode === 40 || keyCode === 13 || keyCode === 27 || keyCode === 9)) {
@@ -334,7 +339,7 @@ export class MultiSelectComponent extends React.Component {
334
339
 
335
340
  const suggestionsLen = suggestions.length;
336
341
 
337
- if (suggestionsLen && isPopupOpen && keyCode === 38) {
342
+ if (suggestionsLen && isPopupOpen && keyCode === 38 && allowKeyboardActions) {
338
343
  //up arrow
339
344
 
340
345
  /*if (hoverOption === 0) { //disable first to last option higlight
@@ -345,7 +350,7 @@ export class MultiSelectComponent extends React.Component {
345
350
  hoverOption: hoverOption - 1
346
351
  });
347
352
  }
348
- } else if (suggestionsLen && isPopupOpen && keyCode === 40) {
353
+ } else if (suggestionsLen && isPopupOpen && keyCode === 40 && allowKeyboardActions) {
349
354
  //down arrow
350
355
 
351
356
  /*else if (hoverOption === suggestionsLen - 1 || hoverOption === null) {
@@ -362,8 +367,8 @@ export class MultiSelectComponent extends React.Component {
362
367
  hoverOption: hoverOption + 1
363
368
  });
364
369
  }
365
- } else if (keyCode === 13) {
366
- //enter key
370
+ } else if (keyCode === 13 && allowKeyboardActions) {
371
+ //enter ke
367
372
  const selectedOption = suggestions[hoverOption] || {};
368
373
  const {
369
374
  id
@@ -727,14 +732,16 @@ export class MultiSelectComponent extends React.Component {
727
732
  needToCloseOnSelect,
728
733
  togglePopup,
729
734
  selectedOptions: propSelectedOptions,
730
- disabledOptions = dummyArray
735
+ disabledOptions = dummyArray,
736
+ limit
731
737
  } = this.props;
732
738
  const {
733
739
  newSelectedOptions
734
740
  } = filterSelectedOptions({
735
741
  selectedOptions,
736
742
  propSelectedOptions,
737
- disabledOptions
743
+ disabledOptions,
744
+ limit
738
745
  });
739
746
  const selectedOptionsLen = newSelectedOptions.length;
740
747
  const allSelectedOptionsDetails = [];
@@ -894,10 +901,10 @@ export class MultiSelectComponent extends React.Component {
894
901
  searchStr
895
902
  } = this.state;
896
903
  const {
897
- clearText = 'Clear all'
904
+ clearText = MULTISELECT_I18N_KEYS.clearText
898
905
  } = i18nKeys;
899
906
  const {
900
- clearLabel = 'Clear all',
907
+ clearLabel = MULTISELECT_I18N_KEYS.clearLabel,
901
908
  ariaLabelledby
902
909
  } = a11y;
903
910
  let {
@@ -1034,7 +1041,8 @@ export class MultiSelectComponent extends React.Component {
1034
1041
  boxSize,
1035
1042
  isLoading,
1036
1043
  selectAllText,
1037
- needSelectAll
1044
+ needSelectAll,
1045
+ limit
1038
1046
  } = this.props;
1039
1047
  const {
1040
1048
  selectedOptions,
@@ -1045,7 +1053,8 @@ export class MultiSelectComponent extends React.Component {
1045
1053
  selectedOptionIds
1046
1054
  } = this.state;
1047
1055
  const {
1048
- searchText = 'Searching...'
1056
+ searchText = MULTISELECT_I18N_KEYS.searchText,
1057
+ limitReachedMessage = MULTISELECT_I18N_KEYS.limitReachedMessage
1049
1058
  } = i18nKeys;
1050
1059
  const suggestions = this.handleFilterSuggestions();
1051
1060
  const setAriaId = this.getNextAriaId();
@@ -1099,7 +1108,7 @@ export class MultiSelectComponent extends React.Component {
1099
1108
  onClick: this.handlePopupClose
1100
1109
  }, /*#__PURE__*/React.createElement("div", {
1101
1110
  className: style.effect
1102
- }, this.getSelectionUI(true))) : null, needSelectAll ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
1111
+ }, this.getSelectionUI(true))) : null, needSelectAll && !(limit >= 0) ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
1103
1112
  onSelect: this.handleSelectAll,
1104
1113
  selectAllText: selectAllText,
1105
1114
  suggestions: suggestions,
@@ -1125,7 +1134,9 @@ export class MultiSelectComponent extends React.Component {
1125
1134
  selectedOptions: selectedOptionIds,
1126
1135
  a11y: {
1127
1136
  role: 'option'
1128
- }
1137
+ },
1138
+ limit: limit,
1139
+ limitReachedMessage: limitReachedMessage
1129
1140
  }) : /*#__PURE__*/React.createElement(EmptyState, {
1130
1141
  isLoading: isFetchingOptions,
1131
1142
  options: options,
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import { MultiSelectWithAvatar_propTypes } from "./props/propTypes";
4
4
  import { MultiSelectWithAvatar_defaultProps } from "./props/defaultProps";
5
5
  import { defaultProps as MobileHeader_defaultProps } from "./MobileHeader/props/defaultProps";
6
+ import { MULTISELECT_I18N_KEYS } from "./constants";
6
7
  /**** Components ****/
7
8
 
8
9
  import { MultiSelectComponent } from "./MultiSelect";
@@ -93,11 +94,15 @@ class MultiSelectWithAvatarComponent extends MultiSelectComponent {
93
94
  needEffect,
94
95
  isLoading,
95
96
  keepSelectedOptions,
96
- customProps
97
+ customProps,
98
+ limit
97
99
  } = this.props;
98
100
  let {
99
101
  SuggestionsProps = {}
100
102
  } = customProps;
103
+ let {
104
+ limitReachedMessage = MULTISELECT_I18N_KEYS.limitReachedMessage
105
+ } = i18nKeys;
101
106
  i18nKeys = Object.assign({}, MobileHeader_defaultProps.i18nKeys, i18nKeys, {
102
107
  emptyText: i18nKeys.emptyText || emptyMessage,
103
108
  searchEmptyText: i18nKeys.searchEmptyText || searchEmptyMessage,
@@ -158,7 +163,7 @@ class MultiSelectWithAvatarComponent extends MultiSelectComponent {
158
163
  onClick: this.handlePopupClose
159
164
  }, /*#__PURE__*/React.createElement("div", {
160
165
  className: style.effect
161
- }, this.getSelectionUI(true)))) : null, needSelectAll ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
166
+ }, this.getSelectionUI(true)))) : null, needSelectAll && !(limit >= 0) ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, {
162
167
  onSelect: this.handleSelectAll,
163
168
  selectAllText: selectAllText,
164
169
  suggestions: suggestions,
@@ -184,6 +189,8 @@ class MultiSelectWithAvatarComponent extends MultiSelectComponent {
184
189
  a11y: {
185
190
  role: 'option'
186
191
  },
192
+ limit: limit,
193
+ limitReachedMessage: limitReachedMessage,
187
194
  ...SuggestionsProps
188
195
  }) : /*#__PURE__*/React.createElement(EmptyState, {
189
196
  isLoading: isFetchingOptions,
@@ -22,10 +22,12 @@ export default class SelectedOptions extends React.PureComponent {
22
22
  onSelect,
23
23
  size,
24
24
  palette,
25
- dataId
25
+ dataId,
26
+ limit
26
27
  } = this.props;
27
28
  const isDarkPalette = palette === 'dark' ? 'dark' : 'danger';
28
- return /*#__PURE__*/React.createElement(React.Fragment, null, selectedOptions.map(option => {
29
+ const selectedData = limit && limit > 0 ? selectedOptions.slice(0, limit) : selectedOptions;
30
+ return /*#__PURE__*/React.createElement(React.Fragment, null, selectedData.map(option => {
29
31
  const {
30
32
  id,
31
33
  value,
@@ -28,12 +28,15 @@ export default class Suggestions extends React.PureComponent {
28
28
  palette,
29
29
  htmlId,
30
30
  a11y,
31
- needMultiLineText
31
+ needMultiLineText,
32
+ limit,
33
+ limitReachedMessage
32
34
  } = this.props;
33
35
  const {
34
36
  ariaParentRole,
35
37
  ariaMultiselectable
36
38
  } = a11y;
39
+ const selectedOptionsLength = selectedOptions.length;
37
40
  return /*#__PURE__*/React.createElement(Container, {
38
41
  isCover: false,
39
42
  role: ariaParentRole,
@@ -58,13 +61,14 @@ export default class Suggestions extends React.PureComponent {
58
61
  } = suggestion;
59
62
  const isActive = activeId === id || selectedOptions.indexOf(id) >= 0;
60
63
  const isHighlight = hoverOption === index || id === hoverId ? true : false;
64
+ const isLimitReached = selectedOptionsLength >= limit && !isActive;
61
65
  const list_a11y = Object.assign({}, a11y, {
62
66
  ariaSelected: isActive,
63
67
  ariaLabel: value,
64
68
  'data-a11y-list-active': isHighlight
65
69
  });
66
70
  const commonProps = {
67
- isDisabled,
71
+ isDisabled: isDisabled ? isDisabled : isLimitReached,
68
72
  needMultiLineText,
69
73
  ...listItemCustomProps
70
74
  };
@@ -76,6 +80,10 @@ export default class Suggestions extends React.PureComponent {
76
80
  };
77
81
  }
78
82
 
83
+ if (isLimitReached) {
84
+ commonProps.disableTitle = limitReachedMessage;
85
+ }
86
+
79
87
  if (optionType === 'avatar') {
80
88
  return /*#__PURE__*/React.createElement(ListItemWithAvatar, { ...commonProps,
81
89
  autoHover: false,
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
3
  import MultiSelect from "../MultiSelect";
4
+ const testData = ['text1', 'text2', 'text3', 'text4', 'text5', 'text6', 'text7', 'text8', 'text9', 'text10'];
5
+ const testSelectedData = ['text1', 'text2', 'text3'];
4
6
  describe('MultiSelect', () => {
5
7
  test('rendering the defult props', () => {
6
8
  const {
@@ -8,4 +10,27 @@ describe('MultiSelect', () => {
8
10
  } = render( /*#__PURE__*/React.createElement(MultiSelect, null));
9
11
  expect(asFragment()).toMatchSnapshot();
10
12
  });
13
+ test('rendering with limit feature', () => {
14
+ const {
15
+ asFragment
16
+ } = render( /*#__PURE__*/React.createElement(MultiSelect, {
17
+ valueField: "id",
18
+ textField: "text",
19
+ options: testData,
20
+ selectedOptions: testSelectedData,
21
+ needSelectAll: true,
22
+ selectAllText: "Select All",
23
+ placeHolder: "Select Text",
24
+ i18nKeys: {
25
+ clearText: 'Clear Selected Items',
26
+ loadingText: 'Fetching...',
27
+ emptyText: 'No Options .',
28
+ noMoreText: 'No More Options .',
29
+ searchEmptyText: 'No Matches Found .'
30
+ },
31
+ needResponsive: true,
32
+ limit: 3
33
+ }));
34
+ expect(asFragment()).toMatchSnapshot();
35
+ });
11
36
  });
@@ -1,6 +1,53 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
3
  import Suggestions from "../Suggestions";
4
+ const sampleData = [{
5
+ "id": 2,
6
+ "value": "text2",
7
+ "optionType": "default",
8
+ "listItemProps": {
9
+ "style": {
10
+ "color": "red"
11
+ }
12
+ }
13
+ }, {
14
+ "id": 3,
15
+ "value": "text3",
16
+ "optionType": "default",
17
+ "listItemProps": {
18
+ "style": {
19
+ "color": "blue"
20
+ }
21
+ }
22
+ }, {
23
+ "id": 4,
24
+ "value": "text4",
25
+ "optionType": "default"
26
+ }, {
27
+ "id": 5,
28
+ "value": "text5",
29
+ "optionType": "default"
30
+ }, {
31
+ "id": 6,
32
+ "value": "text6",
33
+ "optionType": "default"
34
+ }, {
35
+ "id": 7,
36
+ "value": "text7",
37
+ "optionType": "default"
38
+ }, {
39
+ "id": 8,
40
+ "value": "text8",
41
+ "optionType": "default"
42
+ }, {
43
+ "id": 9,
44
+ "value": "text9",
45
+ "optionType": "default"
46
+ }, {
47
+ "id": 10,
48
+ "value": "text10",
49
+ "optionType": "default"
50
+ }];
4
51
  describe('Suggestions', () => {
5
52
  test('rendering the defult props', () => {
6
53
  const {
@@ -10,4 +57,15 @@ describe('Suggestions', () => {
10
57
  }));
11
58
  expect(asFragment()).toMatchSnapshot();
12
59
  });
60
+ test('rendering with limit props', () => {
61
+ const {
62
+ asFragment
63
+ } = render( /*#__PURE__*/React.createElement(Suggestions, {
64
+ selectedOptions: [1, 2, 3, 4],
65
+ suggestions: sampleData,
66
+ limit: 3,
67
+ limitReachedMessage: "Limit Reached"
68
+ }));
69
+ expect(asFragment()).toMatchSnapshot();
70
+ });
13
71
  });