downshift 8.3.2 → 8.4.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.
@@ -13,7 +13,8 @@ declare function getA11yStatusMessage<Item>({ isOpen, resultCount, previousResul
13
13
  export declare const defaultProps: {
14
14
  getA11yStatusMessage: typeof getA11yStatusMessage;
15
15
  isItemDisabled(): boolean;
16
- itemToString: (item: any) => string;
16
+ itemToString(item: any): string;
17
+ itemToKey(item: any): any;
17
18
  stateReducer: (s: Object, a: Object) => Object;
18
19
  getA11ySelectionMessage: (selectionParameters: Object) => string;
19
20
  scrollIntoView: typeof import("../../utils").scrollIntoView;
@@ -44,7 +44,8 @@ export function getDefaultValue(props: any, propKey: any, defaultStateValues?: {
44
44
  inputValue: string;
45
45
  }): any;
46
46
  export namespace defaultProps {
47
- export { itemToString };
47
+ export function itemToString(item: any): string;
48
+ export function itemToKey(item: any): any;
48
49
  export { stateReducer };
49
50
  export { getA11ySelectionMessage };
50
51
  export { scrollIntoView };
@@ -156,8 +157,8 @@ export namespace commonDropdownPropTypes {
156
157
  Node: PropTypes.Validator<(...args: any[]) => any>;
157
158
  }>>;
158
159
  export { environment_1 as environment };
159
- const itemToString_1: PropTypes.Requireable<(...args: any[]) => any>;
160
- export { itemToString_1 as itemToString };
160
+ export const itemToString: PropTypes.Requireable<(...args: any[]) => any>;
161
+ export const itemToKey: PropTypes.Requireable<(...args: any[]) => any>;
161
162
  const stateReducer_1: PropTypes.Requireable<(...args: any[]) => any>;
162
163
  export { stateReducer_1 as stateReducer };
163
164
  }
@@ -168,7 +169,6 @@ export namespace commonPropTypes { }
168
169
  export function useIsInitialMount(): boolean;
169
170
  import { noop } from "../utils";
170
171
  import React from "react";
171
- declare function itemToString(item: any): string;
172
172
  /**
173
173
  * Default state reducer that returns the changes.
174
174
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "downshift",
3
- "version": "8.3.2",
3
+ "version": "8.4.0",
4
4
  "description": "🏎 A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete, combobox or select dropdown components.",
5
5
  "main": "dist/downshift.cjs.js",
6
6
  "react-native": "dist/downshift.native.cjs.js",
@@ -1562,8 +1562,8 @@ function stateReducer(s, a) {
1562
1562
  */
1563
1563
  function getA11ySelectionMessage(selectionParameters) {
1564
1564
  var selectedItem = selectionParameters.selectedItem,
1565
- itemToStringLocal = selectionParameters.itemToString;
1566
- return selectedItem ? itemToStringLocal(selectedItem) + " has been selected." : '';
1565
+ itemToString = selectionParameters.itemToString;
1566
+ return selectedItem ? itemToString(selectedItem) + " has been selected." : '';
1567
1567
  }
1568
1568
 
1569
1569
  /**
@@ -1633,9 +1633,6 @@ function getItemAndIndex(itemProp, indexProp, items, errorMessage) {
1633
1633
  }
1634
1634
  return [item, index];
1635
1635
  }
1636
- function itemToString(item) {
1637
- return item ? String(item) : '';
1638
- }
1639
1636
  function isAcceptedCharacterKey(key) {
1640
1637
  return /^\S{1}$/.test(key);
1641
1638
  }
@@ -1714,7 +1711,12 @@ function useControlledReducer$1(reducer, props, createInitialState, isStateEqual
1714
1711
  return [getState(state, props), dispatch];
1715
1712
  }
1716
1713
  var defaultProps$3 = {
1717
- itemToString: itemToString,
1714
+ itemToString: function itemToString(item) {
1715
+ return item ? String(item) : '';
1716
+ },
1717
+ itemToKey: function itemToKey(item) {
1718
+ return item;
1719
+ },
1718
1720
  stateReducer: stateReducer,
1719
1721
  getA11ySelectionMessage: getA11ySelectionMessage,
1720
1722
  scrollIntoView: scrollIntoView,
@@ -1751,7 +1753,9 @@ function getInitialState$2(props) {
1751
1753
  var highlightedIndex = getInitialValue$1(props, 'highlightedIndex');
1752
1754
  var inputValue = getInitialValue$1(props, 'inputValue');
1753
1755
  return {
1754
- highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.indexOf(selectedItem) : highlightedIndex,
1756
+ highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.findIndex(function (item) {
1757
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
1758
+ }) : highlightedIndex,
1755
1759
  isOpen: isOpen,
1756
1760
  selectedItem: selectedItem,
1757
1761
  inputValue: inputValue
@@ -1760,7 +1764,8 @@ function getInitialState$2(props) {
1760
1764
  function getHighlightedIndexOnOpen(props, state, offset) {
1761
1765
  var items = props.items,
1762
1766
  initialHighlightedIndex = props.initialHighlightedIndex,
1763
- defaultHighlightedIndex = props.defaultHighlightedIndex;
1767
+ defaultHighlightedIndex = props.defaultHighlightedIndex,
1768
+ itemToKey = props.itemToKey;
1764
1769
  var selectedItem = state.selectedItem,
1765
1770
  highlightedIndex = state.highlightedIndex;
1766
1771
  if (items.length === 0) {
@@ -1775,7 +1780,9 @@ function getHighlightedIndexOnOpen(props, state, offset) {
1775
1780
  return defaultHighlightedIndex;
1776
1781
  }
1777
1782
  if (selectedItem) {
1778
- return items.indexOf(selectedItem);
1783
+ return items.findIndex(function (item) {
1784
+ return itemToKey(selectedItem) === itemToKey(item);
1785
+ });
1779
1786
  }
1780
1787
  if (offset === 0) {
1781
1788
  return -1;
@@ -2034,6 +2041,7 @@ var commonPropTypes = {
2034
2041
  Node: PropTypes__default["default"].func.isRequired
2035
2042
  }),
2036
2043
  itemToString: PropTypes__default["default"].func,
2044
+ itemToKey: PropTypes__default["default"].func,
2037
2045
  stateReducer: PropTypes__default["default"].func
2038
2046
  };
2039
2047
 
@@ -2236,7 +2244,9 @@ function downshiftSelectReducer(state, action) {
2236
2244
  {
2237
2245
  var lowercasedKey = action.key;
2238
2246
  var inputValue = "" + state.inputValue + lowercasedKey;
2239
- var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.indexOf(state.selectedItem) : state.highlightedIndex;
2247
+ var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.findIndex(function (item) {
2248
+ return props.itemToKey(item) === props.itemToKey(state.selectedItem);
2249
+ }) : state.highlightedIndex;
2240
2250
  var highlightedIndex = getItemIndexByCharacterKey({
2241
2251
  keysSoFar: inputValue,
2242
2252
  highlightedIndex: prevHighlightedIndex,
@@ -2838,13 +2848,21 @@ function useControlledReducer(reducer, props, createInitialState, isStateEqual)
2838
2848
  if (!isControlledProp(props, 'selectedItem')) {
2839
2849
  return;
2840
2850
  }
2841
- if (!isInitialMount &&
2842
- // on first mount we already have the proper inputValue for a initial selected item.
2843
- props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem)) {
2844
- dispatch({
2845
- type: ControlledPropUpdatedSelectedItem,
2846
- inputValue: props.itemToString(props.selectedItem)
2847
- });
2851
+ if (!isInitialMount // on first mount we already have the proper inputValue for a initial selected item.
2852
+ ) {
2853
+ var shouldCallDispatch;
2854
+ if (props.selectedItemChanged === undefined) {
2855
+ shouldCallDispatch = props.itemToKey(props.selectedItem) !== props.itemToKey(previousSelectedItemRef.current);
2856
+ } else {
2857
+ console.warn("The \"selectedItemChanged\" is deprecated. Please use \"itemToKey instead\". https://github.com/downshift-js/downshift/blob/master/src/hooks/useCombobox/README.md#selecteditemchanged");
2858
+ shouldCallDispatch = props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem);
2859
+ }
2860
+ if (shouldCallDispatch) {
2861
+ dispatch({
2862
+ type: ControlledPropUpdatedSelectedItem,
2863
+ inputValue: props.itemToString(props.selectedItem)
2864
+ });
2865
+ }
2848
2866
  }
2849
2867
  previousSelectedItemRef.current = state.selectedItem === previousSelectedItemRef.current ? props.selectedItem : state.selectedItem;
2850
2868
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2861,9 +2879,6 @@ if (process.env.NODE_ENV !== 'production') {
2861
2879
  };
2862
2880
  }
2863
2881
  var defaultProps$1 = _extends__default["default"]({}, defaultProps$3, {
2864
- selectedItemChanged: function selectedItemChanged(prevItem, item) {
2865
- return prevItem !== item;
2866
- },
2867
2882
  getA11yStatusMessage: getA11yStatusMessage$1,
2868
2883
  isItemDisabled: function isItemDisabled() {
2869
2884
  return false;
@@ -3507,6 +3522,7 @@ var propTypes = _extends__default["default"]({}, commonPropTypes, {
3507
3522
  });
3508
3523
  var defaultProps = {
3509
3524
  itemToString: defaultProps$3.itemToString,
3525
+ itemToKey: defaultProps$3.itemToKey,
3510
3526
  stateReducer: defaultProps$3.stateReducer,
3511
3527
  environment: defaultProps$3.environment,
3512
3528
  getA11yRemovalMessage: getA11yRemovalMessage,
@@ -3621,7 +3637,9 @@ function downshiftMultipleSelectionReducer(state, action) {
3621
3637
  case FunctionRemoveSelectedItem:
3622
3638
  {
3623
3639
  var _newActiveIndex = activeIndex;
3624
- var selectedItemIndex = selectedItems.indexOf(selectedItem);
3640
+ var selectedItemIndex = selectedItems.findIndex(function (item) {
3641
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
3642
+ });
3625
3643
  if (selectedItemIndex < 0) {
3626
3644
  break;
3627
3645
  }
@@ -3705,8 +3723,10 @@ function useMultipleSelection(userProps) {
3705
3723
  return;
3706
3724
  }
3707
3725
  if (selectedItems.length < previousSelectedItemsRef.current.length) {
3708
- var removedSelectedItem = previousSelectedItemsRef.current.find(function (item) {
3709
- return selectedItems.indexOf(item) < 0;
3726
+ var removedSelectedItem = previousSelectedItemsRef.current.find(function (selectedItem) {
3727
+ return selectedItems.findIndex(function (item) {
3728
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
3729
+ }) < 0;
3710
3730
  });
3711
3731
  setStatus(getA11yRemovalMessage({
3712
3732
  itemToString: itemToString,
@@ -3730,7 +3750,8 @@ function useMultipleSelection(userProps) {
3730
3750
  } else if (selectedItemRefs.current[activeIndex]) {
3731
3751
  selectedItemRefs.current[activeIndex].focus();
3732
3752
  }
3733
- }, [activeIndex, isInitialMount]);
3753
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3754
+ }, [activeIndex]);
3734
3755
  useControlPropsValidator({
3735
3756
  props: props,
3736
3757
  state: state
@@ -1549,8 +1549,8 @@ function stateReducer(s, a) {
1549
1549
  */
1550
1550
  function getA11ySelectionMessage(selectionParameters) {
1551
1551
  var selectedItem = selectionParameters.selectedItem,
1552
- itemToStringLocal = selectionParameters.itemToString;
1553
- return selectedItem ? itemToStringLocal(selectedItem) + " has been selected." : '';
1552
+ itemToString = selectionParameters.itemToString;
1553
+ return selectedItem ? itemToString(selectedItem) + " has been selected." : '';
1554
1554
  }
1555
1555
 
1556
1556
  /**
@@ -1620,9 +1620,6 @@ function getItemAndIndex(itemProp, indexProp, items, errorMessage) {
1620
1620
  }
1621
1621
  return [item, index];
1622
1622
  }
1623
- function itemToString(item) {
1624
- return item ? String(item) : '';
1625
- }
1626
1623
  function isAcceptedCharacterKey(key) {
1627
1624
  return /^\S{1}$/.test(key);
1628
1625
  }
@@ -1701,7 +1698,12 @@ function useControlledReducer$1(reducer, props, createInitialState, isStateEqual
1701
1698
  return [getState(state, props), dispatch];
1702
1699
  }
1703
1700
  var defaultProps$3 = {
1704
- itemToString: itemToString,
1701
+ itemToString: function itemToString(item) {
1702
+ return item ? String(item) : '';
1703
+ },
1704
+ itemToKey: function itemToKey(item) {
1705
+ return item;
1706
+ },
1705
1707
  stateReducer: stateReducer,
1706
1708
  getA11ySelectionMessage: getA11ySelectionMessage,
1707
1709
  scrollIntoView: scrollIntoView,
@@ -1738,7 +1740,9 @@ function getInitialState$2(props) {
1738
1740
  var highlightedIndex = getInitialValue$1(props, 'highlightedIndex');
1739
1741
  var inputValue = getInitialValue$1(props, 'inputValue');
1740
1742
  return {
1741
- highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.indexOf(selectedItem) : highlightedIndex,
1743
+ highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.findIndex(function (item) {
1744
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
1745
+ }) : highlightedIndex,
1742
1746
  isOpen: isOpen,
1743
1747
  selectedItem: selectedItem,
1744
1748
  inputValue: inputValue
@@ -1747,7 +1751,8 @@ function getInitialState$2(props) {
1747
1751
  function getHighlightedIndexOnOpen(props, state, offset) {
1748
1752
  var items = props.items,
1749
1753
  initialHighlightedIndex = props.initialHighlightedIndex,
1750
- defaultHighlightedIndex = props.defaultHighlightedIndex;
1754
+ defaultHighlightedIndex = props.defaultHighlightedIndex,
1755
+ itemToKey = props.itemToKey;
1751
1756
  var selectedItem = state.selectedItem,
1752
1757
  highlightedIndex = state.highlightedIndex;
1753
1758
  if (items.length === 0) {
@@ -1762,7 +1767,9 @@ function getHighlightedIndexOnOpen(props, state, offset) {
1762
1767
  return defaultHighlightedIndex;
1763
1768
  }
1764
1769
  if (selectedItem) {
1765
- return items.indexOf(selectedItem);
1770
+ return items.findIndex(function (item) {
1771
+ return itemToKey(selectedItem) === itemToKey(item);
1772
+ });
1766
1773
  }
1767
1774
  if (offset === 0) {
1768
1775
  return -1;
@@ -2021,6 +2028,7 @@ var commonPropTypes = {
2021
2028
  Node: PropTypes.func.isRequired
2022
2029
  }),
2023
2030
  itemToString: PropTypes.func,
2031
+ itemToKey: PropTypes.func,
2024
2032
  stateReducer: PropTypes.func
2025
2033
  };
2026
2034
 
@@ -2223,7 +2231,9 @@ function downshiftSelectReducer(state, action) {
2223
2231
  {
2224
2232
  var lowercasedKey = action.key;
2225
2233
  var inputValue = "" + state.inputValue + lowercasedKey;
2226
- var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.indexOf(state.selectedItem) : state.highlightedIndex;
2234
+ var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.findIndex(function (item) {
2235
+ return props.itemToKey(item) === props.itemToKey(state.selectedItem);
2236
+ }) : state.highlightedIndex;
2227
2237
  var highlightedIndex = getItemIndexByCharacterKey({
2228
2238
  keysSoFar: inputValue,
2229
2239
  highlightedIndex: prevHighlightedIndex,
@@ -2825,13 +2835,21 @@ function useControlledReducer(reducer, props, createInitialState, isStateEqual)
2825
2835
  if (!isControlledProp(props, 'selectedItem')) {
2826
2836
  return;
2827
2837
  }
2828
- if (!isInitialMount &&
2829
- // on first mount we already have the proper inputValue for a initial selected item.
2830
- props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem)) {
2831
- dispatch({
2832
- type: ControlledPropUpdatedSelectedItem,
2833
- inputValue: props.itemToString(props.selectedItem)
2834
- });
2838
+ if (!isInitialMount // on first mount we already have the proper inputValue for a initial selected item.
2839
+ ) {
2840
+ var shouldCallDispatch;
2841
+ if (props.selectedItemChanged === undefined) {
2842
+ shouldCallDispatch = props.itemToKey(props.selectedItem) !== props.itemToKey(previousSelectedItemRef.current);
2843
+ } else {
2844
+ console.warn("The \"selectedItemChanged\" is deprecated. Please use \"itemToKey instead\". https://github.com/downshift-js/downshift/blob/master/src/hooks/useCombobox/README.md#selecteditemchanged");
2845
+ shouldCallDispatch = props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem);
2846
+ }
2847
+ if (shouldCallDispatch) {
2848
+ dispatch({
2849
+ type: ControlledPropUpdatedSelectedItem,
2850
+ inputValue: props.itemToString(props.selectedItem)
2851
+ });
2852
+ }
2835
2853
  }
2836
2854
  previousSelectedItemRef.current = state.selectedItem === previousSelectedItemRef.current ? props.selectedItem : state.selectedItem;
2837
2855
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2848,9 +2866,6 @@ if (process.env.NODE_ENV !== 'production') {
2848
2866
  };
2849
2867
  }
2850
2868
  var defaultProps$1 = _extends({}, defaultProps$3, {
2851
- selectedItemChanged: function selectedItemChanged(prevItem, item) {
2852
- return prevItem !== item;
2853
- },
2854
2869
  getA11yStatusMessage: getA11yStatusMessage$1,
2855
2870
  isItemDisabled: function isItemDisabled() {
2856
2871
  return false;
@@ -3494,6 +3509,7 @@ var propTypes = _extends({}, commonPropTypes, {
3494
3509
  });
3495
3510
  var defaultProps = {
3496
3511
  itemToString: defaultProps$3.itemToString,
3512
+ itemToKey: defaultProps$3.itemToKey,
3497
3513
  stateReducer: defaultProps$3.stateReducer,
3498
3514
  environment: defaultProps$3.environment,
3499
3515
  getA11yRemovalMessage: getA11yRemovalMessage,
@@ -3608,7 +3624,9 @@ function downshiftMultipleSelectionReducer(state, action) {
3608
3624
  case FunctionRemoveSelectedItem:
3609
3625
  {
3610
3626
  var _newActiveIndex = activeIndex;
3611
- var selectedItemIndex = selectedItems.indexOf(selectedItem);
3627
+ var selectedItemIndex = selectedItems.findIndex(function (item) {
3628
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
3629
+ });
3612
3630
  if (selectedItemIndex < 0) {
3613
3631
  break;
3614
3632
  }
@@ -3692,8 +3710,10 @@ function useMultipleSelection(userProps) {
3692
3710
  return;
3693
3711
  }
3694
3712
  if (selectedItems.length < previousSelectedItemsRef.current.length) {
3695
- var removedSelectedItem = previousSelectedItemsRef.current.find(function (item) {
3696
- return selectedItems.indexOf(item) < 0;
3713
+ var removedSelectedItem = previousSelectedItemsRef.current.find(function (selectedItem) {
3714
+ return selectedItems.findIndex(function (item) {
3715
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
3716
+ }) < 0;
3697
3717
  });
3698
3718
  setStatus(getA11yRemovalMessage({
3699
3719
  itemToString: itemToString,
@@ -3717,7 +3737,8 @@ function useMultipleSelection(userProps) {
3717
3737
  } else if (selectedItemRefs.current[activeIndex]) {
3718
3738
  selectedItemRefs.current[activeIndex].focus();
3719
3739
  }
3720
- }, [activeIndex, isInitialMount]);
3740
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3741
+ }, [activeIndex]);
3721
3742
  useControlPropsValidator({
3722
3743
  props: props,
3723
3744
  state: state
@@ -1831,8 +1831,8 @@
1831
1831
  */
1832
1832
  function getA11ySelectionMessage(selectionParameters) {
1833
1833
  var selectedItem = selectionParameters.selectedItem,
1834
- itemToStringLocal = selectionParameters.itemToString;
1835
- return selectedItem ? itemToStringLocal(selectedItem) + " has been selected." : '';
1834
+ itemToString = selectionParameters.itemToString;
1835
+ return selectedItem ? itemToString(selectedItem) + " has been selected." : '';
1836
1836
  }
1837
1837
 
1838
1838
  /**
@@ -1902,9 +1902,6 @@
1902
1902
  }
1903
1903
  return [item, index];
1904
1904
  }
1905
- function itemToString(item) {
1906
- return item ? String(item) : '';
1907
- }
1908
1905
  function isAcceptedCharacterKey(key) {
1909
1906
  return /^\S{1}$/.test(key);
1910
1907
  }
@@ -1983,7 +1980,12 @@
1983
1980
  return [getState(state, props), dispatch];
1984
1981
  }
1985
1982
  var defaultProps$3 = {
1986
- itemToString: itemToString,
1983
+ itemToString: function itemToString(item) {
1984
+ return item ? String(item) : '';
1985
+ },
1986
+ itemToKey: function itemToKey(item) {
1987
+ return item;
1988
+ },
1987
1989
  stateReducer: stateReducer,
1988
1990
  getA11ySelectionMessage: getA11ySelectionMessage,
1989
1991
  scrollIntoView: scrollIntoView,
@@ -2020,7 +2022,9 @@
2020
2022
  var highlightedIndex = getInitialValue$1(props, 'highlightedIndex');
2021
2023
  var inputValue = getInitialValue$1(props, 'inputValue');
2022
2024
  return {
2023
- highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.indexOf(selectedItem) : highlightedIndex,
2025
+ highlightedIndex: highlightedIndex < 0 && selectedItem && isOpen ? props.items.findIndex(function (item) {
2026
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
2027
+ }) : highlightedIndex,
2024
2028
  isOpen: isOpen,
2025
2029
  selectedItem: selectedItem,
2026
2030
  inputValue: inputValue
@@ -2029,7 +2033,8 @@
2029
2033
  function getHighlightedIndexOnOpen(props, state, offset) {
2030
2034
  var items = props.items,
2031
2035
  initialHighlightedIndex = props.initialHighlightedIndex,
2032
- defaultHighlightedIndex = props.defaultHighlightedIndex;
2036
+ defaultHighlightedIndex = props.defaultHighlightedIndex,
2037
+ itemToKey = props.itemToKey;
2033
2038
  var selectedItem = state.selectedItem,
2034
2039
  highlightedIndex = state.highlightedIndex;
2035
2040
  if (items.length === 0) {
@@ -2044,7 +2049,9 @@
2044
2049
  return defaultHighlightedIndex;
2045
2050
  }
2046
2051
  if (selectedItem) {
2047
- return items.indexOf(selectedItem);
2052
+ return items.findIndex(function (item) {
2053
+ return itemToKey(selectedItem) === itemToKey(item);
2054
+ });
2048
2055
  }
2049
2056
  if (offset === 0) {
2050
2057
  return -1;
@@ -2303,6 +2310,7 @@
2303
2310
  Node: PropTypes__default["default"].func.isRequired
2304
2311
  }),
2305
2312
  itemToString: PropTypes__default["default"].func,
2313
+ itemToKey: PropTypes__default["default"].func,
2306
2314
  stateReducer: PropTypes__default["default"].func
2307
2315
  };
2308
2316
 
@@ -2536,7 +2544,9 @@
2536
2544
  {
2537
2545
  var lowercasedKey = action.key;
2538
2546
  var inputValue = "" + state.inputValue + lowercasedKey;
2539
- var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.indexOf(state.selectedItem) : state.highlightedIndex;
2547
+ var prevHighlightedIndex = !state.isOpen && state.selectedItem ? props.items.findIndex(function (item) {
2548
+ return props.itemToKey(item) === props.itemToKey(state.selectedItem);
2549
+ }) : state.highlightedIndex;
2540
2550
  var highlightedIndex = getItemIndexByCharacterKey({
2541
2551
  keysSoFar: inputValue,
2542
2552
  highlightedIndex: prevHighlightedIndex,
@@ -3138,13 +3148,21 @@
3138
3148
  if (!isControlledProp(props, 'selectedItem')) {
3139
3149
  return;
3140
3150
  }
3141
- if (!isInitialMount &&
3142
- // on first mount we already have the proper inputValue for a initial selected item.
3143
- props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem)) {
3144
- dispatch({
3145
- type: ControlledPropUpdatedSelectedItem,
3146
- inputValue: props.itemToString(props.selectedItem)
3147
- });
3151
+ if (!isInitialMount // on first mount we already have the proper inputValue for a initial selected item.
3152
+ ) {
3153
+ var shouldCallDispatch;
3154
+ if (props.selectedItemChanged === undefined) {
3155
+ shouldCallDispatch = props.itemToKey(props.selectedItem) !== props.itemToKey(previousSelectedItemRef.current);
3156
+ } else {
3157
+ console.warn("The \"selectedItemChanged\" is deprecated. Please use \"itemToKey instead\". https://github.com/downshift-js/downshift/blob/master/src/hooks/useCombobox/README.md#selecteditemchanged");
3158
+ shouldCallDispatch = props.selectedItemChanged(previousSelectedItemRef.current, props.selectedItem);
3159
+ }
3160
+ if (shouldCallDispatch) {
3161
+ dispatch({
3162
+ type: ControlledPropUpdatedSelectedItem,
3163
+ inputValue: props.itemToString(props.selectedItem)
3164
+ });
3165
+ }
3148
3166
  }
3149
3167
  previousSelectedItemRef.current = state.selectedItem === previousSelectedItemRef.current ? props.selectedItem : state.selectedItem;
3150
3168
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -3161,9 +3179,6 @@
3161
3179
  };
3162
3180
  }
3163
3181
  var defaultProps$1 = _extends({}, defaultProps$3, {
3164
- selectedItemChanged: function selectedItemChanged(prevItem, item) {
3165
- return prevItem !== item;
3166
- },
3167
3182
  getA11yStatusMessage: getA11yStatusMessage$1,
3168
3183
  isItemDisabled: function isItemDisabled() {
3169
3184
  return false;
@@ -3807,6 +3822,7 @@
3807
3822
  });
3808
3823
  var defaultProps = {
3809
3824
  itemToString: defaultProps$3.itemToString,
3825
+ itemToKey: defaultProps$3.itemToKey,
3810
3826
  stateReducer: defaultProps$3.stateReducer,
3811
3827
  environment: defaultProps$3.environment,
3812
3828
  getA11yRemovalMessage: getA11yRemovalMessage,
@@ -3921,7 +3937,9 @@
3921
3937
  case FunctionRemoveSelectedItem:
3922
3938
  {
3923
3939
  var _newActiveIndex = activeIndex;
3924
- var selectedItemIndex = selectedItems.indexOf(selectedItem);
3940
+ var selectedItemIndex = selectedItems.findIndex(function (item) {
3941
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
3942
+ });
3925
3943
  if (selectedItemIndex < 0) {
3926
3944
  break;
3927
3945
  }
@@ -4005,8 +4023,10 @@
4005
4023
  return;
4006
4024
  }
4007
4025
  if (selectedItems.length < previousSelectedItemsRef.current.length) {
4008
- var removedSelectedItem = previousSelectedItemsRef.current.find(function (item) {
4009
- return selectedItems.indexOf(item) < 0;
4026
+ var removedSelectedItem = previousSelectedItemsRef.current.find(function (selectedItem) {
4027
+ return selectedItems.findIndex(function (item) {
4028
+ return props.itemToKey(item) === props.itemToKey(selectedItem);
4029
+ }) < 0;
4010
4030
  });
4011
4031
  setStatus(getA11yRemovalMessage({
4012
4032
  itemToString: itemToString,
@@ -4030,7 +4050,8 @@
4030
4050
  } else if (selectedItemRefs.current[activeIndex]) {
4031
4051
  selectedItemRefs.current[activeIndex].focus();
4032
4052
  }
4033
- }, [activeIndex, isInitialMount]);
4053
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4054
+ }, [activeIndex]);
4034
4055
  useControlPropsValidator({
4035
4056
  props: props,
4036
4057
  state: state