@entur/dropdown 5.0.28 → 5.1.0-beta.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.
@@ -803,105 +803,99 @@ var useNormalizedItems = function useNormalizedItems(items) {
803
803
  }, [items]);
804
804
  };
805
805
 
806
- var useIsMounted = function useIsMounted() {
807
- var isMountedRef = React.useRef(true);
808
- React.useEffect(function () {
809
- return function () {
810
- isMountedRef.current = false;
811
- };
812
- }, []);
813
- return isMountedRef.current;
814
- };
815
- var reducer = function reducer(_state, action) {
816
- switch (action.type) {
817
- case 'request results':
818
- return {
819
- items: [],
820
- loading: true
821
- };
822
- case 'received results':
823
- return {
824
- items: action.payload,
825
- loading: false
826
- };
827
- }
828
- };
829
806
  var useResolvedItems = function useResolvedItems( /** The list of items, or an async function that resolves the list of items */
830
807
  itemsOrItemsResolver, /** The time to wait after the input changes to the fetchItems method is called */
831
808
  debounceTimeout) {
832
809
  if (debounceTimeout === void 0) {
833
810
  debounceTimeout = 250;
834
811
  }
835
- var isItemsFunction = typeof itemsOrItemsResolver === 'function';
836
- // Here, we normalize the itemsResolver argument to an async function, so we
812
+ var itemsIsAFunction = typeof itemsOrItemsResolver === 'function';
813
+ var _React$useState = React.useState(itemsIsAFunction ? [] : itemsOrItemsResolver),
814
+ items = _React$useState[0],
815
+ setItems = _React$useState[1];
816
+ var _React$useState2 = React.useState(false),
817
+ loading = _React$useState2[0],
818
+ setLoading = _React$useState2[1];
819
+ var abortControllerRef = React.useRef(new AbortController());
820
+ // We normalize the itemsResolver argument to an async function, so we
837
821
  // can use it without thinking about the differences later
838
822
  var itemsResolver = React.useMemo(function () {
839
- return isItemsFunction ? itemsOrItemsResolver : function () {
823
+ if (itemsIsAFunction) return itemsOrItemsResolver;
824
+ return function () {
840
825
  return Promise.resolve(itemsOrItemsResolver);
841
826
  };
842
- }, [itemsOrItemsResolver, isItemsFunction]);
843
- var _React$useReducer = React.useReducer(reducer, {
844
- items: isItemsFunction ? [] : itemsOrItemsResolver,
845
- loading: false
846
- }),
847
- _React$useReducer$ = _React$useReducer[0],
848
- items = _React$useReducer$.items,
849
- loading = _React$useReducer$.loading,
850
- dispatch = _React$useReducer[1];
851
- // This is a way to check whether or not the dropdown is still in the
852
- // document. We use it below to make sure we're not updating the state of
853
- // an unmounted component.
854
- var isMounted = useIsMounted();
855
- // Next, let's create the fetching function. This should be called whenever
856
- // the input value changes
857
- var fetchItems = React.useCallback( /*#__PURE__*/function () {
827
+ }, [itemsOrItemsResolver, itemsIsAFunction]);
828
+ // This should be called whenever the input value changes
829
+ var updateItems = /*#__PURE__*/function () {
858
830
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(inputValue) {
859
- var resolvedItems;
831
+ var _abortControllerRef$c;
832
+ var abortController, _abortControllerRef$c2, _abortControllerRef$c3, resolvedItems;
860
833
  return _regeneratorRuntime().wrap(function _callee$(_context) {
861
834
  while (1) {
862
835
  switch (_context.prev = _context.next) {
863
836
  case 0:
864
- if (isMounted) {
865
- _context.next = 2;
837
+ // The abortController handles cleanup of the previous request and unmounting
838
+ if (abortControllerRef != null && abortControllerRef.current) abortControllerRef == null ? void 0 : (_abortControllerRef$c = abortControllerRef.current) == null ? void 0 : _abortControllerRef$c.abort();
839
+ abortController = new AbortController();
840
+ abortControllerRef.current = abortController;
841
+ setLoading(true);
842
+ _context.prev = 4;
843
+ _context.next = 7;
844
+ return itemsResolver(inputValue != null ? inputValue : '', abortControllerRef);
845
+ case 7:
846
+ resolvedItems = _context.sent;
847
+ if (!(abortControllerRef != null && (_abortControllerRef$c2 = abortControllerRef.current) != null && (_abortControllerRef$c3 = _abortControllerRef$c2.signal) != null && _abortControllerRef$c3.aborted)) {
848
+ _context.next = 11;
866
849
  break;
867
850
  }
851
+ console.warn('Avbryt den asynkrone funksjonen din med signalet fra AbortController-en for å for å unngå minnelekkasje.', 'Funksjonen bør kaste en DOMException med navnet "AbortError" når den avbrytes.', '', '\n\nSe eksempel her: https://design.entur.no/komponenter/skjemaelementer/dropdown#s%C3%B8kbar-dropdown-med-valg-fra-nettverkskall-bassert-p%C3%A5-tekstinput', '\nLes mer om AbortController her: https://developer.mozilla.org/en-US/docs/Web/API/AbortController');
868
852
  return _context.abrupt("return");
869
- case 2:
870
- dispatch({
871
- type: 'request results'
872
- });
873
- _context.next = 5;
874
- return itemsResolver(inputValue);
875
- case 5:
876
- resolvedItems = _context.sent;
877
- if (isMounted) {
878
- dispatch({
879
- type: 'received results',
880
- payload: resolvedItems
881
- });
853
+ case 11:
854
+ setLoading(false);
855
+ setItems(resolvedItems);
856
+ _context.next = 21;
857
+ break;
858
+ case 15:
859
+ _context.prev = 15;
860
+ _context.t0 = _context["catch"](4);
861
+ if (!(_context.t0 && typeof _context.t0 === 'object' && 'name' in _context.t0 && _context.t0.name === 'AbortError')) {
862
+ _context.next = 19;
863
+ break;
882
864
  }
883
- case 7:
865
+ return _context.abrupt("return");
866
+ case 19:
867
+ console.warn('The following error was received but not handled inside Entur Designsystems useResolvedItems hook:');
868
+ throw _context.t0;
869
+ case 21:
884
870
  case "end":
885
871
  return _context.stop();
886
872
  }
887
873
  }
888
- }, _callee);
874
+ }, _callee, null, [[4, 15]]);
889
875
  }));
890
- return function (_x) {
876
+ return function updateItems(_x) {
891
877
  return _ref.apply(this, arguments);
892
878
  };
893
- }(), [itemsResolver, isMounted]);
879
+ }();
880
+ var debouncedFetchItems = utils.useDebounce(updateItems, debounceTimeout);
894
881
  var normalizedItems = useNormalizedItems(items);
882
+ React.useEffect(function () {
883
+ // send abort signal to previous request on unmount for cleanup
884
+ return function () {
885
+ var _abortControllerRef$c4;
886
+ return abortControllerRef == null ? void 0 : (_abortControllerRef$c4 = abortControllerRef.current) == null ? void 0 : _abortControllerRef$c4.abort('Component unmounted');
887
+ };
888
+ }, []);
895
889
  React.useEffect(function () {
896
890
  // Let's fetch the list initially if it's specified
897
- if (isItemsFunction) {
898
- fetchItems('');
891
+ if (itemsIsAFunction) {
892
+ debouncedFetchItems('');
899
893
  }
900
- }, [isItemsFunction, fetchItems]);
894
+ }, [itemsIsAFunction]);
901
895
  return {
902
896
  items: normalizedItems,
903
- loading: isItemsFunction ? loading : false,
904
- fetchItems: utils.debounce(fetchItems, debounceTimeout)
897
+ loading: itemsIsAFunction ? loading : false,
898
+ fetchItems: debouncedFetchItems
905
899
  };
906
900
  };
907
901
 
@@ -1332,7 +1326,7 @@ var DropdownList = function DropdownList(_ref) {
1332
1326
  style: _extends({
1333
1327
  display: isOpen ? 'inline-block' : 'none'
1334
1328
  }, rest.style, listStyle)
1335
- }), listItems.length > 0 && listItems.map(function (item, index) {
1329
+ }), !loading && listItems.length > 0 && listItems.map(function (item, index) {
1336
1330
  var itemIsSelectAll = item.value === (selectAllItem == null ? void 0 : selectAllItem.value);
1337
1331
  if (itemIsSelectAll && listItems.length <= 2) return null;
1338
1332
  return React.createElement("li", _extends({