expensify-common 2.0.166 → 2.0.167

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.
@@ -193,22 +193,37 @@ class Combobox extends react_1.default.Component {
193
193
  }
194
194
  // eslint-disable-next-line react/no-unsafe
195
195
  UNSAFE_componentWillReceiveProps(nextProps) {
196
- if (!nextProps.value || (0, isEqual_1.default)(nextProps.value, this.state.currentValue)) {
197
- return;
196
+ if (nextProps.value && !(0, isEqual_1.default)(nextProps.value, this.state.currentValue)) {
197
+ this.setValue(nextProps.value);
198
198
  }
199
- this.setValue(nextProps.value);
200
199
  if (nextProps.options !== undefined) {
201
200
  // If the options have an id property, we use that to compare them and determine if they changed, if not
202
201
  // we'll use the whole options array.
203
- if ((0, has_1.default)(nextProps.options, '0.id')) {
204
- if (nextProps.options.some((option, index) => !(0, isEqual_1.default)(option.id, this.props.options[index].id)) ||
205
- nextProps.alreadySelectedOptions.some((alreadySelectedOption, index) => !(0, isEqual_1.default)(alreadySelectedOption.id, this.props.alreadySelectedOptions[index].id))) {
202
+ const optionsChanged = (0, has_1.default)(nextProps.options, '0.id')
203
+ ? nextProps.options.some((option, index) => !(0, isEqual_1.default)(option.id, this.props.options[index] && this.props.options[index].id))
204
+ : !(0, isEqual_1.default)(nextProps.options, this.props.options);
205
+ // Check if alreadySelectedOptions changed - compare by id if available, otherwise by value or full comparison
206
+ const hasAlreadySelectedId = nextProps.alreadySelectedOptions && nextProps.alreadySelectedOptions.length > 0 && (0, has_1.default)(nextProps.alreadySelectedOptions[0], 'id');
207
+ const alreadySelectedChanged = hasAlreadySelectedId
208
+ ? nextProps.alreadySelectedOptions.length !== this.props.alreadySelectedOptions.length ||
209
+ nextProps.alreadySelectedOptions.some((alreadySelectedOption, index) => {
210
+ const prevOption = this.props.alreadySelectedOptions[index];
211
+ return !prevOption || !(0, isEqual_1.default)(alreadySelectedOption.id, prevOption.id);
212
+ })
213
+ : !(0, isEqual_1.default)(nextProps.alreadySelectedOptions, this.props.alreadySelectedOptions);
214
+ if (optionsChanged || alreadySelectedChanged) {
215
+ // If only alreadySelectedOptions changed and dropdown is open, just update options without resetting
216
+ if (!optionsChanged && alreadySelectedChanged && this.state.isDropdownOpen) {
217
+ const { currentValue } = this.state;
218
+ this.setState(() => ({
219
+ options: this.getTruncatedOptions(currentValue, nextProps.alreadySelectedOptions),
220
+ }));
221
+ }
222
+ else {
223
+ // Options changed or dropdown is closed - do full reset
206
224
  this.reset(false, nextProps.options, nextProps.alreadySelectedOptions);
207
225
  }
208
226
  }
209
- else if (!(0, isEqual_1.default)(nextProps.options, this.props.options) || !(0, isEqual_1.default)(nextProps.alreadySelectedOptions, this.props.alreadySelectedOptions)) {
210
- this.reset(false, nextProps.options, nextProps.alreadySelectedOptions);
211
- }
212
227
  }
213
228
  if (nextProps.openOnInit !== undefined && !(0, isEqual_1.default)(nextProps.openOnInit, this.props.openOnInit)) {
214
229
  this.setState({
@@ -431,7 +446,7 @@ class Combobox extends react_1.default.Component {
431
446
  const dividerIndex = this.options.findIndex(findDivider);
432
447
  // Split into two arrays everything before and after the divider (if the divider does not exist then we'll return a single array)
433
448
  const splitOptions = dividerIndex ? [this.options.slice(0, dividerIndex + 1), this.options.slice(dividerIndex + 1)] : [this.options];
434
- const formatOption = (option) => (Object.assign({ focused: false, isSelected: option.selected && ((0, isEqual_1.default)(option.value, currentValue) || !!alreadySelected.find((item) => item.value === option.value)) }, option));
449
+ const formatOption = (option, index) => (Object.assign({ focused: false, isSelected: (option.selected && (0, isEqual_1.default)(option.value, currentValue)) || !!alreadySelected.find((item) => item.value === option.value), originalIndex: index }, option));
435
450
  const sortByOption = (o) => {
436
451
  // Unselectable text-only entries (isFake: true) go to the bottom and selected entries go to the top only if alwaysShowSelectedOnTop was passed
437
452
  if (o.showLast) {
@@ -440,11 +455,24 @@ class Combobox extends react_1.default.Component {
440
455
  return o.isSelected && this.props.alwaysShowSelectedOnTop ? 0 : 1;
441
456
  };
442
457
  // Take each array and format it, sort it, and move selected items to top (if applicable)
443
- const formatOptions = (array) => array
444
- .map(formatOption)
445
- .sort((a, b) => sortByOption(a) - sortByOption(b))
446
- .slice(0, this.props.maxItemsToShow);
447
- const truncatedOptions = splitOptions.map(formatOptions).flat();
458
+ const formatOptions = (array, arrayStartIndex) => {
459
+ return array
460
+ .map((option, index) => formatOption(option, arrayStartIndex + index))
461
+ .sort((a, b) => {
462
+ const sortDiff = sortByOption(a) - sortByOption(b);
463
+ // If sort priority is the same, preserve original order using originalIndex
464
+ return sortDiff !== 0 ? sortDiff : a.originalIndex - b.originalIndex;
465
+ })
466
+ .slice(0, this.props.maxItemsToShow);
467
+ };
468
+ let cumulativeIndex = 0;
469
+ const truncatedOptions = splitOptions
470
+ .map((array) => {
471
+ const result = formatOptions(array, cumulativeIndex);
472
+ cumulativeIndex += array.length;
473
+ return result;
474
+ })
475
+ .flat();
448
476
  if (!truncatedOptions.length) {
449
477
  truncatedOptions.push({
450
478
  text: 'No items',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expensify-common",
3
- "version": "2.0.166",
3
+ "version": "2.0.167",
4
4
  "author": "Expensify, Inc.",
5
5
  "description": "Expensify libraries and components shared across different repos",
6
6
  "homepage": "https://expensify.com",