@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
@@ -37,11 +37,13 @@ export const MultiSelect_propTypes = {
37
37
  getRef: PropTypes.func,
38
38
  getTargetRef: PropTypes.func,
39
39
  i18nKeys: PropTypes.shape({
40
+ searchText: PropTypes.string,
40
41
  clearText: PropTypes.string,
41
42
  loadingText: PropTypes.string,
42
43
  emptyText: PropTypes.string,
43
44
  noMoreText: PropTypes.string,
44
- searchEmptyText: PropTypes.string
45
+ searchEmptyText: PropTypes.string,
46
+ limitReachedMessage: PropTypes.string
45
47
  }),
46
48
  a11y: PropTypes.shape({
47
49
  clearLabel: PropTypes.string
@@ -116,7 +118,8 @@ export const MultiSelect_propTypes = {
116
118
  isFocus: PropTypes.bool,
117
119
  allowValueFallback: PropTypes.bool,
118
120
  renderCustomClearComponent: PropTypes.func,
119
- renderCustomToggleIndicator: PropTypes.oneOfType([PropTypes.func, PropTypes.node])
121
+ renderCustomToggleIndicator: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
122
+ limit: PropTypes.number
120
123
  };
121
124
  export const MultiSelectHeader_propTypes = {
122
125
  dataId: PropTypes.string,
@@ -153,7 +156,8 @@ export const SelectedOptions_propTypes = {
153
156
  })),
154
157
  size: PropTypes.oneOf(['medium', 'xmedium']),
155
158
  palette: PropTypes.string,
156
- dataId: PropTypes.string
159
+ dataId: PropTypes.string,
160
+ limit: PropTypes.number
157
161
  };
158
162
  export const Suggestions_propTypes = {
159
163
  a11y: PropTypes.shape({
@@ -183,7 +187,9 @@ export const Suggestions_propTypes = {
183
187
  logo: PropTypes.string,
184
188
  optionType: PropTypes.string,
185
189
  listItemProps: PropTypes.object
186
- }))
190
+ })),
191
+ limit: PropTypes.number,
192
+ limitReachedMessage: PropTypes.string
187
193
  };
188
194
  export const AdvancedGroupMultiSelect_propTypes = {
189
195
  animationStyle: PropTypes.string,
@@ -201,7 +207,8 @@ export const AdvancedGroupMultiSelect_propTypes = {
201
207
  loadingText: PropTypes.string,
202
208
  emptyText: PropTypes.string,
203
209
  noMoreText: PropTypes.string,
204
- searchEmptyText: PropTypes.string
210
+ searchEmptyText: PropTypes.string,
211
+ limitReachedMessage: PropTypes.string
205
212
  }),
206
213
  a11y: PropTypes.shape({
207
214
  clearLabel: PropTypes.string
@@ -255,7 +262,8 @@ export const AdvancedGroupMultiSelect_propTypes = {
255
262
  children: PropTypes.node,
256
263
  dataSelectorId: PropTypes.string,
257
264
  isFocus: PropTypes.bool,
258
- allowValueFallback: PropTypes.bool
265
+ allowValueFallback: PropTypes.bool,
266
+ limit: PropTypes.number
259
267
  };
260
268
  export const AdvancedMultiSelect_propTypes = { ...MultiSelect_propTypes,
261
269
  selectedOptionDetails: PropTypes.string,
@@ -269,68 +277,20 @@ export const AdvancedMultiSelect_propTypes = { ...MultiSelect_propTypes,
269
277
  selectedOptions: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])).isRequired,
270
278
  selectedOptionsLimit: PropTypes.number,
271
279
  getSelectedOptionDetails: PropTypes.func,
272
- emptyMessage: PropTypes.string.isRequired,
273
- isDisabled: PropTypes.bool,
274
- isReadOnly: PropTypes.bool,
275
- needLocalSearch: PropTypes.bool,
276
- needSelectAll: PropTypes.bool,
277
- onChange: PropTypes.func.isRequired,
278
- searchEmptyMessage: PropTypes.string,
279
- placeHolder: PropTypes.string,
280
- selectAllText: PropTypes.string,
281
- textField: PropTypes.string,
282
- valueField: PropTypes.string,
283
280
  imageField: PropTypes.string,
284
281
  iconName: PropTypes.string,
285
282
  prefixText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
286
283
  //For grouping multiSelect
287
284
  optionType: PropTypes.oneOf(['default', 'avatar', 'icon']),
288
- needEffect: PropTypes.bool,
289
285
  secondaryField: PropTypes.string,
290
- animationStyle: PropTypes.string,
291
- defaultDropBoxPosition: PropTypes.oneOf(['bottom', 'top', 'left', 'right']),
292
- dropBoxSize: PropTypes.oneOf(['small', 'medium', 'large']),
293
- isAnimate: PropTypes.bool,
294
- size: PropTypes.oneOf(['medium', 'xmedium']),
295
- textBoxSize: PropTypes.oneOf(['small', 'medium', 'xmedium']),
296
- title: PropTypes.string,
297
- variant: PropTypes.string,
298
286
  dataIdClearIcon: PropTypes.string,
299
287
  dataIdLoading: PropTypes.string,
300
288
  dataIdMultiSelectComp: PropTypes.string,
301
289
  dataIdSelectAllEle: PropTypes.string,
302
-
303
- /**** Popup Props ****/
304
- isPopupOpen: PropTypes.bool,
305
- isPopupReady: PropTypes.bool,
306
- togglePopup: PropTypes.func,
307
- getContainerRef: PropTypes.func,
308
- position: PropTypes.string,
309
- removeClose: PropTypes.func,
310
290
  listItemSize: PropTypes.oneOf(['small', 'medium', 'large']),
311
- needBorder: PropTypes.bool,
312
- htmlId: PropTypes.string,
313
- i18nKeys: PropTypes.shape({
314
- clearText: PropTypes.string,
315
- loadingText: PropTypes.string,
316
- emptyText: PropTypes.string,
317
- noMoreText: PropTypes.string,
318
- searchEmptyText: PropTypes.string
319
- }),
320
- a11y: PropTypes.shape({
321
- clearLabel: PropTypes.string
322
- }),
323
- borderColor: PropTypes.oneOf(['transparent', 'default', 'dark']),
324
- isBoxPaddingNeed: PropTypes.bool,
325
- isSearchClearOnSelect: PropTypes.bool,
326
- disabledOptions: PropTypes.arrayOf(PropTypes.string),
327
- getFooter: PropTypes.func,
328
291
  customProps: PropTypes.shape({
329
292
  SuggestionsProps: PropTypes.object,
330
293
  DropBoxProps: PropTypes.object
331
294
  }),
332
- isLoading: PropTypes.bool,
333
- dataSelectorId: PropTypes.string,
334
- customClass: PropTypes.object,
335
- isFocus: PropTypes.bool
295
+ customClass: PropTypes.object
336
296
  };
package/es/Popup/Popup.js CHANGED
@@ -161,7 +161,11 @@ const Popup = function (Component) {
161
161
  this.handleDropElementStyleUpdate = this.handleDropElementStyleUpdate.bind(this);
162
162
  this.positionRef = /*#__PURE__*/React.createRef();
163
163
  this.rootElement = Registry.getRootElement();
164
- this.popupObserver = new ResizeObserver(this.handlePopupResize); //dropBoxSize
164
+ this.popupObserver = new ResizeObserver(this.handlePopupResize);
165
+ this.cancelRaf = this.cancelRaf.bind(this);
166
+ this.cancelPendingAnimationFrames = this.cancelPendingAnimationFrames.bind(this);
167
+ this.setPositionRafId = null;
168
+ this.resizePositionRafId = null; //dropBoxSize
165
169
 
166
170
  this.size = null;
167
171
  this.isTargetElementVisible = false;
@@ -181,17 +185,18 @@ const Popup = function (Component) {
181
185
  groupPopups.push(this);
182
186
  Registry.popups[group] = groupPopups;
183
187
 
184
- if (Object.keys(Registry.popups).length === 1 && groupPopups.length === 1) {
185
- this.updateListeners(true, CLICK_EVENTS, document);
186
- document.addEventListener('keyup', this.documentKeyupHandler, false); // document.addEventListener('scroll', this.handleScroll, true);
188
+ if (Object.keys(Registry.popups).length === 1 && groupPopups.length === 1 && Registry.listenerPopupRef === undefined) {
189
+ Registry.listenerPopupRef = this;
190
+ Registry.listenerPopupRef.updateListeners(true, CLICK_EVENTS, document);
191
+ document.addEventListener('keyup', Registry.listenerPopupRef.documentKeyupHandler, false); // document.addEventListener('scroll', Registry.listenerPopupRef.handleScroll, true);
187
192
 
188
- window.addEventListener('resize', this.handleResize);
189
- document.addEventListener('mousedown', this.handleDocumentMouseDown, true);
190
- document.addEventListener('focus', this.handleDocumentFocus, true);
193
+ window.addEventListener('resize', Registry.listenerPopupRef.handleResize);
194
+ document.addEventListener('mousedown', Registry.listenerPopupRef.handleDocumentMouseDown, true);
195
+ document.addEventListener('focus', Registry.listenerPopupRef.handleDocumentFocus, true);
191
196
  }
192
197
  }
193
198
 
194
- componentWillReceiveProps(nextProps) {
199
+ UNSAFE_componentWillReceiveProps(nextProps) {
195
200
  const {
196
201
  isPopupOpen
197
202
  } = this.state;
@@ -256,6 +261,20 @@ const Popup = function (Component) {
256
261
  }
257
262
  }
258
263
 
264
+ cancelRaf(refName) {
265
+ const id = this[refName];
266
+
267
+ if (id) {
268
+ cancelAnimationFrame(id);
269
+ this[refName] = null;
270
+ }
271
+ }
272
+
273
+ cancelPendingAnimationFrames() {
274
+ this.cancelRaf('setPositionRafId');
275
+ this.cancelRaf('resizePositionRafId');
276
+ }
277
+
259
278
  componentWillUnmount() {
260
279
  const group = this.getGroup();
261
280
  Registry.popups = Object.keys(Registry.popups).reduce((res, groupName) => {
@@ -284,14 +303,17 @@ const Popup = function (Component) {
284
303
  this.popupObserver.disconnect();
285
304
  }
286
305
 
287
- if (noPopups) {
288
- this.updateListeners(false, CLICK_EVENTS, document);
289
- document.removeEventListener('keyup', this.documentKeyupHandler); // document.removeEventListener('scroll', this.handleScroll);
306
+ if (noPopups && Registry.listenerPopupRef !== undefined) {
307
+ Registry.listenerPopupRef.updateListeners(false, CLICK_EVENTS, document);
308
+ document.removeEventListener('keyup', Registry.listenerPopupRef.documentKeyupHandler); // document.removeEventListener('scroll', Registry.listenerPopupRef.handleScroll);
290
309
 
291
- window.removeEventListener('resize', this.handleResize);
292
- document.removeEventListener('mousedown', this.handleDocumentMouseDown, true);
293
- document.removeEventListener('focus', this.handleDocumentFocus, true);
310
+ window.removeEventListener('resize', Registry.listenerPopupRef.handleResize);
311
+ document.removeEventListener('mousedown', Registry.listenerPopupRef.handleDocumentMouseDown, true);
312
+ document.removeEventListener('focus', Registry.listenerPopupRef.handleDocumentFocus, true);
313
+ Registry.listenerPopupRef = undefined;
294
314
  }
315
+
316
+ this.cancelPendingAnimationFrames();
295
317
  }
296
318
 
297
319
  handleAddingScrollBlock() {
@@ -814,7 +836,8 @@ const Popup = function (Component) {
814
836
  }
815
837
 
816
838
  const setPosition = () => {
817
- requestAnimationFrame(() => {
839
+ this.cancelRaf('setPositionRafId');
840
+ this.setPositionRafId = requestAnimationFrame(() => {
818
841
  const {
819
842
  placeHolderElement,
820
843
  dropElement
@@ -823,7 +846,7 @@ const Popup = function (Component) {
823
846
  position,
824
847
  isPopupReady
825
848
  } = this.state;
826
- const scrollContainer = placeHolderElement.closest('[data-scroll=true]') || document.body;
849
+ const scrollContainer = placeHolderElement ? placeHolderElement.closest('[data-scroll=true]') || document.body : document.body;
827
850
  const betterPosition = viewPort.betterView(dropElement, placeHolderElement, defaultPosition, scrollContainer, {
828
851
  needArrow,
829
852
  isAbsolute,
@@ -852,6 +875,8 @@ const Popup = function (Component) {
852
875
  this.updatePopupState(view, views, viewsOffset, targetOffset, popupOffset, isAbsolute);
853
876
  }
854
877
  }
878
+
879
+ this.setPositionRafId = null;
855
880
  });
856
881
  };
857
882
 
@@ -883,7 +908,8 @@ const Popup = function (Component) {
883
908
 
884
909
  if (placeHolderElement && dropElement) {
885
910
  const scrollContainer = placeHolderElement.closest('[data-scroll=true]') || document.body;
886
- requestAnimationFrame(() => {
911
+ this.cancelRaf('resizePositionRafId');
912
+ this.resizePositionRafId = requestAnimationFrame(() => {
887
913
  const needArrow = this.getNeedArrow(popup);
888
914
  const isAbsolute = this.getIsAbsolutePopup(popup);
889
915
  const customOrder = this.getCustomPositionOrder(popup);
@@ -940,6 +966,8 @@ const Popup = function (Component) {
940
966
  // });
941
967
  // }
942
968
 
969
+
970
+ this.resizePositionRafId = null;
943
971
  });
944
972
  }
945
973
  }
@@ -2,6 +2,7 @@ import { getLibraryConfig } from "../Provider/Config.js";
2
2
  const Registry = {
3
3
  lastOpenedGroup: [],
4
4
  popups: {},
5
+ listenerPopupRef: undefined,
5
6
  scrollBlockedListenerPopupRef: undefined,
6
7
  scrollableListenerPopupRef: undefined,
7
8
 
@@ -119,7 +119,7 @@ export class SelectComponent extends Component {
119
119
  // suggestionContainer.addEventListener('scroll', this.handleScroll);
120
120
  }
121
121
 
122
- componentWillReceiveProps(nextProps) {
122
+ UNSAFE_componentWillReceiveProps(nextProps) {
123
123
  let {
124
124
  selectedValue,
125
125
  isDefaultSelectValue,
@@ -246,7 +246,14 @@ describe('Select -', () => {
246
246
  userEvent.type(within(getByTestId(dropboxTestId)).getByRole('textbox'), '2');
247
247
  expect(getAllByRole(listItemRole)).toHaveLength(1);
248
248
  expect(asFragment()).toMatchSnapshot();
249
- });
249
+ }); // test('Should render the only options matching search value even with additional spaces before and after', () => {
250
+ // const { getByRole, getAllByRole, asFragment, getByTestId } = render(<Select needSearch options={options} />);
251
+ // userEvent.click(getByRole(selectInputRole));
252
+ // userEvent.type(within(getByTestId(dropboxTestId)).getByRole('textbox'), ' 2 ');
253
+ // expect(getAllByRole(listItemRole)).toHaveLength(1);
254
+ // expect(asFragment()).toMatchSnapshot();
255
+ // });
256
+
250
257
  test('Should trigger given onSearch, when type on the search input', async () => {
251
258
  const mockOnSearch = jest.fn();
252
259
  const {
@@ -7,6 +7,8 @@ export const getOptions = props => props.options || dummyArray;
7
7
 
8
8
  const getOptionsOrder = props => props.optionsOrder || dummyArray;
9
9
 
10
+ const getLimit = props => props.limit || 0;
11
+
10
12
  const getSelectedOptionsSel = props => props.selectedOptions || dummyArray;
11
13
 
12
14
  const getSearchStr = props => props.searchStr || '';
@@ -206,10 +208,10 @@ export const makeFormatOptions = () => createSelector([getOptions, getValueField
206
208
  optionsOrder: remvampOptionIds
207
209
  };
208
210
  });
209
- export const makeGetMultiSelectSelectedOptions = () => createSelector([getSelectedOptionsSel, getNormalizedFormatOptions, getSelectedOptionsLength, getAllowValueFallback], (selectedOptions, normalizedFormatOptions, selectedOptionsLength, allowValueFallback) => {
210
- const output = [];
211
- const revampSelectedOptions = [];
212
- const normalizedSelectedOptions = {};
211
+ export const makeGetMultiSelectSelectedOptions = () => createSelector([getSelectedOptionsSel, getNormalizedFormatOptions, getSelectedOptionsLength, getAllowValueFallback, getLimit], (selectedOptions, normalizedFormatOptions, selectedOptionsLength, allowValueFallback, limit) => {
212
+ let output = [];
213
+ let revampSelectedOptions = [];
214
+ let normalizedSelectedOptions = {};
213
215
  selectedOptionsLength = !getIsEmptyValue(selectedOptionsLength) ? selectedOptionsLength : selectedOptions.length;
214
216
 
215
217
  for (let i = 0; i < selectedOptionsLength; i++) {
@@ -234,6 +236,12 @@ export const makeGetMultiSelectSelectedOptions = () => createSelector([getSelect
234
236
  }
235
237
  }
236
238
 
239
+ if (limit && limit > 0) {
240
+ output = output.slice(0, limit);
241
+ revampSelectedOptions = revampSelectedOptions.slice(0, limit);
242
+ normalizedSelectedOptions = Object.fromEntries(Object.entries(normalizedSelectedOptions).slice(0, limit));
243
+ }
244
+
237
245
  return {
238
246
  formatSelectedOptions: output,
239
247
  normalizedSelectedOptions,
@@ -423,7 +431,8 @@ export const filterSelectedOptions = function () {
423
431
  let {
424
432
  selectedOptions = dummyArray,
425
433
  propSelectedOptions = dummyArray,
426
- disabledOptions = dummyArray
434
+ disabledOptions = dummyArray,
435
+ limit
427
436
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
428
437
  // eslint-disable-next-line no-param-reassign
429
438
  selectedOptions = selectedOptions || dummyArray; // eslint-disable-next-line no-param-reassign
@@ -445,8 +454,18 @@ export const filterSelectedOptions = function () {
445
454
 
446
455
  return true;
447
456
  });
457
+ const totalSelectedOptions = [...oldValidSelectedOptions, ...newlyAddedOptions];
458
+
459
+ if (limit && limit > 0) {
460
+ if (totalSelectedOptions.length > limit) {
461
+ return {
462
+ newSelectedOptions: totalSelectedOptions.slice(0, limit)
463
+ };
464
+ }
465
+ }
466
+
448
467
  return {
449
- newSelectedOptions: [...oldValidSelectedOptions, ...newlyAddedOptions]
468
+ newSelectedOptions: totalSelectedOptions
450
469
  };
451
470
  };
452
471
  export const makeGetIsShowClearIcon = () => createSelector([getSelectedOptionsSel, getDisabledOptions], (selectedOptions, disabledOptions) => {
@@ -120,7 +120,7 @@ const Popup = function (Component) {
120
120
  }
121
121
  }
122
122
 
123
- componentWillReceiveProps(nextProps) {
123
+ UNSAFE_componentWillReceiveProps(nextProps) {
124
124
  const {
125
125
  isPopupOpen
126
126
  } = this.state;
@@ -119,7 +119,7 @@ export class SelectComponent extends Component {
119
119
  // suggestionContainer.addEventListener('scroll', this.handleScroll);
120
120
  }
121
121
 
122
- componentWillReceiveProps(nextProps) {
122
+ UNSAFE_componentWillReceiveProps(nextProps) {
123
123
  let {
124
124
  selectedValue,
125
125
  isDefaultSelectValue,
@@ -69,8 +69,8 @@ var Accordion = /*#__PURE__*/function (_React$Component) {
69
69
  });
70
70
  }
71
71
  }, {
72
- key: "componentWillReceiveProps",
73
- value: function componentWillReceiveProps(nextProps) {
72
+ key: "UNSAFE_componentWillReceiveProps",
73
+ value: function UNSAFE_componentWillReceiveProps(nextProps) {
74
74
  if (this.props.selectedItem !== nextProps.selectedItem && !this.props.disableInternalState) {
75
75
  this.setState({
76
76
  selectedItem: nextProps.selectedItem
package/lib/Card/Card.js CHANGED
@@ -184,8 +184,8 @@ var Card = /*#__PURE__*/function (_Component3) {
184
184
  }
185
185
 
186
186
  _createClass(Card, [{
187
- key: "componentWillReceiveProps",
188
- value: function componentWillReceiveProps(nextProps) {
187
+ key: "UNSAFE_componentWillReceiveProps",
188
+ value: function UNSAFE_componentWillReceiveProps(nextProps) {
189
189
  if (this.from !== nextProps.from) {
190
190
  this.from = nextProps.from;
191
191
  }