@entur/dropdown 7.3.9-beta.0 → 8.0.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.
@@ -14,7 +14,7 @@ import { LoadingDots } from "@entur/loader";
14
14
  import { Tooltip } from "@entur/tooltip";
15
15
  const DropdownList = ({
16
16
  ariaLabelChosenSingular = "valgt",
17
- ariaLabelSelectedItem = ", valgt element, trykk for å fjerne",
17
+ ariaLabelSelectedItem = ", valgt element",
18
18
  getItemProps,
19
19
  isOpen,
20
20
  highlightedIndex,
@@ -185,6 +185,7 @@ const SelectedItemTag = ({
185
185
  removeSelectedItem,
186
186
  selectedItem
187
187
  }) => {
188
+ if (!selectedItem) return null;
188
189
  const { tabIndex: _, ...selectedItemProps } = getSelectedItemProps?.({
189
190
  selectedItem,
190
191
  index
@@ -401,6 +402,10 @@ const itemToString = (item) => item ? item.label : "";
401
402
  const itemToKey = (item) => item?.label + item?.value;
402
403
  const isFunctionWithQueryArgument = (object) => typeof object === "function" && object.length > 0;
403
404
  const clamp = (val, min = 1, max = 10) => Math.min(Math.max(val, min), max);
405
+ const resetInputState = (changes) => ({
406
+ ...changes,
407
+ inputValue: EMPTY_INPUT
408
+ });
404
409
  const useMultiselectUtils = ({
405
410
  listItems,
406
411
  selectedItems,
@@ -516,7 +521,6 @@ const SearchableDropdown = React.forwardRef(
516
521
  prepend,
517
522
  readOnly = false,
518
523
  selectedItem: value,
519
- selectOnBlur = false,
520
524
  selectOnTab = false,
521
525
  style,
522
526
  variant = "info",
@@ -543,77 +547,56 @@ const SearchableDropdown = React.forwardRef(
543
547
  if (shouldRefetchItems) fetchItems(inputValue2 ?? EMPTY_INPUT);
544
548
  filterListItems({ inputValue: inputValue2 ?? EMPTY_INPUT });
545
549
  };
546
- const resetInputState = ({
547
- changes
548
- }) => {
549
- return {
550
- ...changes,
551
- inputValue: EMPTY_INPUT
552
- };
553
- };
554
550
  const inputHasFocus = typeof document !== "undefined" ? inputRef?.current === document?.activeElement : false;
555
551
  useEffect(() => {
556
552
  filterListItems({ inputValue });
557
553
  }, [normalizedItems]);
558
- useEffect(() => {
559
- if (selectedItem !== null && !inputHasFocus) {
560
- setShowSelectedItem(true);
561
- updateListItems({ inputValue: EMPTY_INPUT });
562
- setInputValue(EMPTY_INPUT);
563
- }
564
- }, []);
565
554
  const stateReducer = useCallback(
566
555
  (state, {
567
556
  type,
568
557
  changes
569
558
  }) => {
570
- if (changes.highlightedIndex !== void 0 && changes?.highlightedIndex >= 0) {
571
- setLastHighlightedIndex(changes?.highlightedIndex);
572
- }
573
559
  switch (type) {
574
560
  // empty input to show selected item and reset dropdown list on item selection
575
561
  case useCombobox.stateChangeTypes.ItemClick:
576
562
  case useCombobox.stateChangeTypes.InputKeyDownEnter:
577
- return resetInputState({ changes });
563
+ return resetInputState(changes);
578
564
  case useCombobox.stateChangeTypes.InputBlur:
579
565
  return resetInputState({
580
- changes: { ...changes, selectedItem: value }
566
+ ...changes,
567
+ selectedItem: state.selectedItem
581
568
  });
582
569
  case useCombobox.stateChangeTypes.ControlledPropUpdatedSelectedItem:
583
- return resetInputState({ changes });
570
+ return { ...changes, inputValue: state.inputValue };
584
571
  // remove leading whitespace, select element with spacebar on empty input
585
572
  case useCombobox.stateChangeTypes.InputChange: {
586
- const leadingWhitespaceTest = /^\s+/g;
587
573
  const isSpacePressedOnEmptyInput = changes.inputValue === " ";
588
- if (!isSpacePressedOnEmptyInput) setLastHighlightedIndex(0);
589
- if (changes.inputValue?.match(leadingWhitespaceTest)) {
590
- const sanitizedInputValue = changes.inputValue.replace(
591
- leadingWhitespaceTest,
592
- EMPTY_INPUT
593
- );
594
- if (isSpacePressedOnEmptyInput) {
595
- if (!state.isOpen)
596
- return {
597
- ...changes,
598
- inputValue: sanitizedInputValue,
599
- isOpen: true
600
- };
601
- if (changes.highlightedIndex !== void 0) {
602
- return {
603
- ...changes,
604
- inputValue: sanitizedInputValue,
605
- selectedItem: listItems[changes.highlightedIndex]
606
- };
607
- }
608
- }
609
- }
610
- return { ...changes, highlightedIndex: 0 };
574
+ if (!isSpacePressedOnEmptyInput)
575
+ return { ...changes, highlightedIndex: 0 };
576
+ const sanitizedInputValue = (changes.inputValue ?? "").replace(
577
+ /^\s+/,
578
+ EMPTY_INPUT
579
+ );
580
+ if (!state.isOpen)
581
+ return {
582
+ ...changes,
583
+ inputValue: sanitizedInputValue,
584
+ isOpen: true
585
+ };
586
+ const i = changes.highlightedIndex ?? -1;
587
+ if (i >= 0 && i < listItems.length)
588
+ return {
589
+ ...changes,
590
+ inputValue: sanitizedInputValue,
591
+ selectedItem: listItems[i]
592
+ };
593
+ return { ...changes, inputValue: sanitizedInputValue };
611
594
  }
612
595
  default:
613
596
  return changes;
614
597
  }
615
598
  },
616
- [fetchItems, filterListItems, inputHasFocus, resetInputState]
599
+ [listItems, EMPTY_INPUT]
617
600
  );
618
601
  const {
619
602
  isOpen,
@@ -640,9 +623,23 @@ const SearchableDropdown = React.forwardRef(
640
623
  onSelectedItemChange({ selectedItem: newSelectedItem }) {
641
624
  onChange(newSelectedItem);
642
625
  },
626
+ onHighlightedIndexChange: ({ highlightedIndex: highlightedIndex2 }) => {
627
+ if (highlightedIndex2 >= 0) setLastHighlightedIndex(highlightedIndex2);
628
+ },
643
629
  // Accessibility
644
630
  getA11yStatusMessage: (options) => getA11yStatusMessage({ ...options, resultCount: listItems.length })
645
631
  });
632
+ useEffect(() => {
633
+ if (value !== null && !inputHasFocus) {
634
+ setShowSelectedItem(true);
635
+ updateListItems({ inputValue: EMPTY_INPUT });
636
+ setInputValue(EMPTY_INPUT);
637
+ }
638
+ }, [value]);
639
+ const handleOnClear = () => {
640
+ inputRef.current?.focus();
641
+ reset();
642
+ };
646
643
  const { refs, floatingStyles, update } = useFloating({
647
644
  open: isOpen,
648
645
  placement: "bottom-start",
@@ -669,10 +666,39 @@ const SearchableDropdown = React.forwardRef(
669
666
  );
670
667
  }
671
668
  }, [isOpen, refs.reference, refs.floating, update]);
672
- const handleOnClear = () => {
673
- inputRef.current?.focus();
674
- reset();
675
- };
669
+ const labelProps = getLabelProps();
670
+ const toggleButtonProps = getToggleButtonProps({
671
+ "aria-busy": !(loading ?? resolvedItemsLoading) ? void 0 : "true"
672
+ });
673
+ const menuProps = getMenuProps({
674
+ refKey: "innerRef",
675
+ ref: refs.setFloating,
676
+ style: listStyle
677
+ });
678
+ const inputProps = getInputProps({
679
+ onKeyDown(e) {
680
+ if (isOpen && e.key === "Tab") {
681
+ const highlitedItem = listItems[highlightedIndex];
682
+ if (selectOnTab && highlitedItem) {
683
+ selectItem(highlitedItem);
684
+ setShowSelectedItem(true);
685
+ }
686
+ }
687
+ },
688
+ onBlur(e) {
689
+ if (selectedItem !== null) setShowSelectedItem(true);
690
+ onBlur?.(e);
691
+ },
692
+ onFocus(e) {
693
+ if (!readOnly) setShowSelectedItem(false);
694
+ onFocus?.(e);
695
+ },
696
+ disabled,
697
+ readOnly,
698
+ placeholder: selectedItem?.label ?? placeholder,
699
+ tabIndex: disabled || readOnly ? -1 : void 0,
700
+ ref: mergeRefs(inputRef, ref)
701
+ });
676
702
  return /* @__PURE__ */ jsxs(
677
703
  BaseFormControl,
678
704
  {
@@ -687,15 +713,14 @@ const SearchableDropdown = React.forwardRef(
687
713
  feedback,
688
714
  isFilled: selectedItem !== null || inputValue !== EMPTY_INPUT,
689
715
  label,
690
- labelId: getLabelProps().id,
691
- labelProps: getLabelProps(),
716
+ labelId: labelProps.id,
717
+ labelProps,
692
718
  labelTooltip,
693
719
  onClick: (e) => {
694
- if (e.target === e.currentTarget) getInputProps()?.onClick?.(e);
720
+ if (e.target === e.currentTarget) inputProps?.onClick?.(e);
695
721
  onClick?.(e);
696
722
  },
697
723
  onKeyDown,
698
- onFocus,
699
724
  prepend,
700
725
  readOnly,
701
726
  ref: refs.setReference,
@@ -717,11 +742,7 @@ const SearchableDropdown = React.forwardRef(
717
742
  noMatchesText,
718
743
  selectedItems: selectedItem !== null ? [selectedItem] : [],
719
744
  readOnly,
720
- ...getMenuProps({
721
- refKey: "innerRef",
722
- ref: refs.setFloating,
723
- style: listStyle
724
- })
745
+ ...menuProps
725
746
  }
726
747
  ),
727
748
  ...rest,
@@ -736,7 +757,7 @@ const SearchableDropdown = React.forwardRef(
736
757
  onClick: (event) => {
737
758
  if (!disabled && !readOnly) {
738
759
  inputRef.current?.focus();
739
- getInputProps()?.onClick?.(event);
760
+ inputProps?.onClick?.(event);
740
761
  }
741
762
  },
742
763
  tabIndex: readOnly ? 0 : -1,
@@ -749,39 +770,13 @@ const SearchableDropdown = React.forwardRef(
749
770
  className: classNames("eds-dropdown__input eds-form-control", {
750
771
  "eds-dropdown__input--hidden": showSelectedItem
751
772
  }),
752
- ...getInputProps({
753
- onKeyDown(e) {
754
- if (isOpen && e.key === "Tab") {
755
- const highlitedItem = listItems[highlightedIndex];
756
- if ((selectOnTab || selectOnBlur) && highlitedItem) {
757
- selectItem(highlitedItem);
758
- setShowSelectedItem(true);
759
- }
760
- }
761
- },
762
- onBlur(e) {
763
- if (selectedItem !== null) setShowSelectedItem(true);
764
- onBlur?.(e);
765
- },
766
- onFocus() {
767
- if (!readOnly) {
768
- setShowSelectedItem(false);
769
- }
770
- },
771
- disabled,
772
- readOnly,
773
- placeholder: selectedItem?.label ?? placeholder,
774
- tabIndex: disabled || readOnly ? -1 : void 0,
775
- ref: mergeRefs(inputRef, ref)
776
- })
773
+ ...inputProps
777
774
  }
778
775
  ),
779
776
  /* @__PURE__ */ jsx(
780
777
  DropdownFieldAppendix,
781
778
  {
782
- ...getToggleButtonProps({
783
- "aria-busy": !(loading ?? resolvedItemsLoading) ? void 0 : "true"
784
- }),
779
+ ...toggleButtonProps,
785
780
  ariaLabelCloseList,
786
781
  ariaLabelOpenList,
787
782
  clearable,
@@ -826,7 +821,6 @@ const MultiSelect = React.forwardRef(
826
821
  placeholder,
827
822
  readOnly = false,
828
823
  selectedItems = [],
829
- selectOnBlur = false,
830
824
  selectOnTab = false,
831
825
  style,
832
826
  variant = "information",
@@ -857,10 +851,14 @@ const MultiSelect = React.forwardRef(
857
851
  fetchItems
858
852
  } = useResolvedItems(initialItems, debounceTimeout);
859
853
  const isAllNonAsyncItemsSelected = typeof initialItems !== "function" && selectedItems.length === normalizedItems.length;
860
- const selectAll = {
861
- value: useRandomId("select-all"),
862
- label: labelSelectAll
863
- };
854
+ const selectAllUniqueId = useRandomId("select-all");
855
+ const selectAll = React.useMemo(
856
+ () => ({
857
+ value: selectAllUniqueId,
858
+ label: labelSelectAll
859
+ }),
860
+ [labelSelectAll]
861
+ );
864
862
  const summarySelectedItems = React.useMemo(
865
863
  () => ({
866
864
  value: EMPTY_INPUT,
@@ -923,69 +921,57 @@ const MultiSelect = React.forwardRef(
923
921
  });
924
922
  const stateReducer = React.useCallback(
925
923
  (state, {
926
- changes,
927
- type
924
+ type,
925
+ changes
928
926
  }) => {
929
- if (changes.highlightedIndex !== void 0 && changes?.highlightedIndex >= 0) {
930
- setLastHighlightedIndex(changes?.highlightedIndex);
931
- }
932
927
  switch (type) {
933
- // reset input value when leaving input field
934
- case useCombobox.stateChangeTypes.InputBlur:
935
- return {
936
- ...changes,
937
- inputValue: EMPTY_INPUT
938
- };
939
928
  // keep menu open and edit input value on item selection
940
929
  case useCombobox.stateChangeTypes.InputKeyDownEnter:
941
930
  case useCombobox.stateChangeTypes.ItemClick: {
942
931
  return {
943
932
  ...changes,
944
933
  isOpen: true,
945
- inputValue: clearInputOnSelect ? EMPTY_INPUT : inputRef?.current?.value ?? EMPTY_INPUT
934
+ inputValue: clearInputOnSelect ? EMPTY_INPUT : state.inputValue
946
935
  };
947
936
  }
937
+ // reset input value when leaving input field
938
+ case useCombobox.stateChangeTypes.InputBlur: {
939
+ const { selectedItem: _, ...otherChanges } = changes;
940
+ return resetInputState(otherChanges);
941
+ }
948
942
  // edit input value when selected items is updated outside component
949
943
  case useCombobox.stateChangeTypes.ControlledPropUpdatedSelectedItem: {
950
- return {
951
- ...changes,
952
- inputValue: inputRef?.current?.value ?? EMPTY_INPUT
953
- };
944
+ return { ...changes, inputValue: state.inputValue };
954
945
  }
955
946
  // remove leading whitespace, select item with spacebar if input is empty and filter list items
956
947
  case useCombobox.stateChangeTypes.InputChange: {
957
- const leadingWhitespaceTest = /^\s+/g;
958
948
  const isSpacePressedOnEmptyInput = changes.inputValue === " ";
959
949
  if (!isSpacePressedOnEmptyInput)
960
- setLastHighlightedIndex(hideSelectAll ? 0 : 1);
961
- if (changes.inputValue?.match(leadingWhitespaceTest)) {
962
- const sanitizedInputValue = changes.inputValue.replace(
963
- leadingWhitespaceTest,
964
- EMPTY_INPUT
965
- );
966
- if (isSpacePressedOnEmptyInput) {
967
- if (!state.isOpen)
968
- return {
969
- ...changes,
970
- inputValue: sanitizedInputValue,
971
- isOpen: true
972
- };
973
- if (changes.highlightedIndex !== void 0) {
974
- return {
975
- ...changes,
976
- inputValue: sanitizedInputValue,
977
- selectedItem: listItems[changes.highlightedIndex]
978
- };
979
- }
980
- }
981
- }
982
- return { ...changes, highlightedIndex: hideSelectAll ? 0 : 1 };
950
+ return { ...changes, highlightedIndex: hideSelectAll ? 0 : 1 };
951
+ const sanitizedInputValue = (changes.inputValue ?? "").replace(
952
+ /^\s+/,
953
+ EMPTY_INPUT
954
+ );
955
+ if (!state.isOpen)
956
+ return {
957
+ ...changes,
958
+ inputValue: sanitizedInputValue,
959
+ isOpen: true
960
+ };
961
+ const i = changes.highlightedIndex ?? -1;
962
+ if (i >= 0 && i < listItems.length)
963
+ return {
964
+ ...changes,
965
+ inputValue: sanitizedInputValue,
966
+ selectedItem: listItems[i]
967
+ };
968
+ return { ...changes, inputValue: sanitizedInputValue };
983
969
  }
984
970
  default:
985
971
  return changes;
986
972
  }
987
973
  },
988
- [hideSelectAll, normalizedItems, initialItems]
974
+ [hideSelectAll, listItems, clearInputOnSelect]
989
975
  );
990
976
  const {
991
977
  getInputProps,
@@ -995,8 +981,7 @@ const MultiSelect = React.forwardRef(
995
981
  getToggleButtonProps,
996
982
  highlightedIndex,
997
983
  inputValue,
998
- isOpen,
999
- setInputValue
984
+ isOpen
1000
985
  } = useCombobox({
1001
986
  defaultHighlightedIndex: lastHighlightedIndex,
1002
987
  // after selection, highlight previously selected item.
@@ -1014,6 +999,9 @@ const MultiSelect = React.forwardRef(
1014
999
  onChange: setSelectedItems
1015
1000
  });
1016
1001
  },
1002
+ onHighlightedIndexChange: ({ highlightedIndex: highlightedIndex2 }) => {
1003
+ if (highlightedIndex2 >= 0) setLastHighlightedIndex(highlightedIndex2);
1004
+ },
1017
1005
  // Accessibility
1018
1006
  getA11yStatusMessage: (options) => getA11yStatusMessage({
1019
1007
  ...options,
@@ -1052,6 +1040,42 @@ const MultiSelect = React.forwardRef(
1052
1040
  inputRef.current?.focus();
1053
1041
  reset();
1054
1042
  };
1043
+ const dropdownProps = getDropdownProps({
1044
+ preventKeyAction: isOpen,
1045
+ value: inputValue ?? EMPTY_INPUT,
1046
+ ref: mergeRefs(inputRef, ref)
1047
+ });
1048
+ const inputProps = getInputProps({
1049
+ onKeyDown: (e) => {
1050
+ if (selectOnTab && isOpen && e.key === "Tab") {
1051
+ const highlitedItem = listItems[highlightedIndex];
1052
+ if (!highlitedItem) return;
1053
+ const shouldSkipTabSelection = clickedItemIsSelectAll(highlitedItem) || !clickedItemIsSelectAll(highlitedItem) && clickedItemIsInSelectedItems(highlitedItem);
1054
+ if (shouldSkipTabSelection) return;
1055
+ handleListItemClicked({
1056
+ clickedItem: highlitedItem,
1057
+ onChange: setSelectedItems
1058
+ });
1059
+ }
1060
+ },
1061
+ onBlur,
1062
+ onFocus,
1063
+ ...dropdownProps,
1064
+ className: "eds-dropdown__input eds-form-control",
1065
+ disabled: readOnly || disabled,
1066
+ placeholder,
1067
+ tabIndex: disabled || readOnly ? -1 : void 0
1068
+ });
1069
+ const labelProps = getLabelProps();
1070
+ const menuProps = getMenuProps({
1071
+ "aria-multiselectable": true,
1072
+ refKey: "innerRef",
1073
+ ref: refs.setFloating,
1074
+ style: listStyle
1075
+ });
1076
+ const toggleButtonProps = getToggleButtonProps({
1077
+ "aria-busy": !(loading ?? resolvedItemsLoading) ? void 0 : "true"
1078
+ });
1055
1079
  return /* @__PURE__ */ jsxs(
1056
1080
  BaseFormControl,
1057
1081
  {
@@ -1066,15 +1090,14 @@ const MultiSelect = React.forwardRef(
1066
1090
  feedback,
1067
1091
  isFilled: hasSelectedItems || inputValue !== EMPTY_INPUT,
1068
1092
  label,
1069
- labelId: getLabelProps().id,
1070
- labelProps: getLabelProps(),
1093
+ labelId: labelProps.id,
1094
+ labelProps,
1071
1095
  labelTooltip,
1072
1096
  onClick: (e) => {
1073
- if (e.target === e.currentTarget) getInputProps()?.onClick?.(e);
1097
+ if (e.target === e.currentTarget) inputProps?.onClick?.(e);
1074
1098
  onClick?.(e);
1075
1099
  },
1076
1100
  onKeyDown,
1077
- onFocus,
1078
1101
  readOnly,
1079
1102
  ref: refs.setReference,
1080
1103
  style,
@@ -1096,12 +1119,7 @@ const MultiSelect = React.forwardRef(
1096
1119
  selectAllItem: selectAll,
1097
1120
  selectedItems,
1098
1121
  readOnly,
1099
- ...getMenuProps({
1100
- "aria-multiselectable": true,
1101
- refKey: "innerRef",
1102
- ref: refs.setFloating,
1103
- style: listStyle
1104
- })
1122
+ ...menuProps
1105
1123
  }
1106
1124
  ),
1107
1125
  ...rest,
@@ -1116,7 +1134,7 @@ const MultiSelect = React.forwardRef(
1116
1134
  }
1117
1135
  ),
1118
1136
  children: [
1119
- selectedItems.length > 1 ? /* @__PURE__ */ jsx(VisuallyHidden, { onClick: inputRef.current?.focus, children: ariaLabelJumpToInput }) : null,
1137
+ selectedItems.length > 1 ? /* @__PURE__ */ jsx(VisuallyHidden, { onClick: () => inputRef.current?.focus(), children: ariaLabelJumpToInput }) : null,
1120
1138
  selectedItems.length <= maxChips ? selectedItems.map((selectedItem, index) => /* @__PURE__ */ jsx(
1121
1139
  SelectedItemTag,
1122
1140
  {
@@ -1144,47 +1162,14 @@ const MultiSelect = React.forwardRef(
1144
1162
  selectedItem: summarySelectedItems
1145
1163
  }
1146
1164
  ),
1147
- /* @__PURE__ */ jsx(
1148
- "input",
1149
- {
1150
- ...getInputProps({
1151
- onKeyDown: (e) => {
1152
- if (selectOnTab && isOpen && e.key === "Tab") {
1153
- const highlitedItem = listItems[highlightedIndex];
1154
- if (!highlitedItem) return;
1155
- const shouldSkipTabSelection = clickedItemIsSelectAll(highlitedItem) || !clickedItemIsSelectAll(highlitedItem) && clickedItemIsInSelectedItems(highlitedItem);
1156
- if (shouldSkipTabSelection) return;
1157
- handleListItemClicked({
1158
- clickedItem: highlitedItem,
1159
- onChange: setSelectedItems
1160
- });
1161
- }
1162
- },
1163
- onBlur: (e) => {
1164
- setInputValue("");
1165
- onBlur?.(e);
1166
- },
1167
- ...getDropdownProps({
1168
- preventKeyAction: isOpen,
1169
- value: inputValue ?? EMPTY_INPUT,
1170
- ref: mergeRefs(inputRef, ref)
1171
- }),
1172
- className: "eds-dropdown__input eds-form-control",
1173
- disabled: readOnly || disabled,
1174
- placeholder,
1175
- tabIndex: disabled || readOnly ? -1 : void 0
1176
- })
1177
- }
1178
- )
1165
+ /* @__PURE__ */ jsx("input", { ...inputProps })
1179
1166
  ]
1180
1167
  }
1181
1168
  ),
1182
1169
  /* @__PURE__ */ jsx(
1183
1170
  DropdownFieldAppendix,
1184
1171
  {
1185
- ...getToggleButtonProps({
1186
- "aria-busy": !(loading ?? resolvedItemsLoading) ? void 0 : "true"
1187
- }),
1172
+ ...toggleButtonProps,
1188
1173
  ariaLabelCloseList,
1189
1174
  ariaLabelOpenList,
1190
1175
  clearable,
@@ -1227,7 +1212,6 @@ const Dropdown = React.forwardRef(
1227
1212
  prepend,
1228
1213
  readOnly = false,
1229
1214
  selectedItem,
1230
- selectOnBlur = false,
1231
1215
  selectOnTab = false,
1232
1216
  style,
1233
1217
  variant = "information",
@@ -1248,22 +1232,20 @@ const Dropdown = React.forwardRef(
1248
1232
  items: normalizedItems,
1249
1233
  defaultHighlightedIndex: selectedItem ? void 0 : 0,
1250
1234
  selectedItem,
1251
- stateReducer(_, { changes, type }) {
1235
+ stateReducer(state, { changes, type }) {
1252
1236
  const toggleButtonIsFocused = typeof document !== "undefined" && document.activeElement === refs.reference.current;
1253
1237
  switch (type) {
1254
1238
  case useSelect.stateChangeTypes.ToggleButtonKeyDownArrowDown:
1255
1239
  case useSelect.stateChangeTypes.ToggleButtonKeyDownArrowUp:
1256
1240
  if (!toggleButtonIsFocused) return { ...changes, isOpen: false };
1241
+ break;
1242
+ case useSelect.stateChangeTypes.ToggleButtonBlur:
1243
+ return { ...changes, selectedItem: state.selectedItem };
1257
1244
  }
1258
1245
  return changes;
1259
1246
  },
1260
- onStateChange({ type, selectedItem: newSelectedItem }) {
1261
- switch (type) {
1262
- case useSelect.stateChangeTypes.ToggleButtonBlur:
1263
- if (!selectOnBlur) return;
1264
- }
1265
- if (newSelectedItem === void 0) return;
1266
- onChange?.(newSelectedItem ?? null);
1247
+ onSelectedItemChange({ selectedItem: newSelectedItem }) {
1248
+ onChange?.(newSelectedItem);
1267
1249
  },
1268
1250
  itemToString
1269
1251
  });
@@ -1294,9 +1276,35 @@ const Dropdown = React.forwardRef(
1294
1276
  }
1295
1277
  }, [isOpen, refs.reference, refs.floating, update]);
1296
1278
  const handleOnClear = () => {
1297
- reset();
1298
1279
  refs.reference.current?.focus();
1280
+ reset();
1299
1281
  };
1282
+ const labelProps = getLabelProps({
1283
+ isFilled
1284
+ });
1285
+ const toggleButtonProps = getToggleButtonProps({
1286
+ ref: mergeRefs(ref, refs.setReference),
1287
+ "aria-disabled": disabled,
1288
+ "aria-label": disabled ? "Disabled dropdown" : "",
1289
+ disabled,
1290
+ readOnly,
1291
+ label,
1292
+ labelId: labelProps?.id,
1293
+ tabIndex: disabled || readOnly ? -1 : 0,
1294
+ onKeyDown(e) {
1295
+ if (isOpen && e.key === "Tab") {
1296
+ const highlitedItem = normalizedItems[highlightedIndex];
1297
+ if (selectOnTab && highlitedItem && highlitedItem !== selectedItem) {
1298
+ selectItem(highlitedItem);
1299
+ }
1300
+ }
1301
+ }
1302
+ });
1303
+ const menuProps = getMenuProps({
1304
+ refKey: "innerRef",
1305
+ ref: refs.setFloating,
1306
+ style: listStyle
1307
+ });
1300
1308
  return /* @__PURE__ */ jsxs(
1301
1309
  BaseFormControl,
1302
1310
  {
@@ -1305,31 +1313,12 @@ const Dropdown = React.forwardRef(
1305
1313
  }),
1306
1314
  disableLabelAnimation,
1307
1315
  feedback,
1308
- isFilled,
1309
- labelProps: getLabelProps(),
1316
+ labelProps,
1310
1317
  labelTooltip,
1311
1318
  prepend,
1312
1319
  style,
1313
1320
  variant,
1314
- ...getToggleButtonProps({
1315
- ref: mergeRefs(ref, refs.setReference),
1316
- "aria-disabled": disabled,
1317
- "aria-label": disabled ? "Disabled dropdown" : "",
1318
- disabled,
1319
- readOnly,
1320
- label,
1321
- labelId: getLabelProps()?.id,
1322
- children: void 0,
1323
- tabIndex: disabled || readOnly ? -1 : 0,
1324
- onKeyDown(e) {
1325
- if (isOpen && e.key === "Tab") {
1326
- const highlitedItem = normalizedItems[highlightedIndex];
1327
- if ((selectOnTab || selectOnBlur) && highlitedItem && highlitedItem !== selectedItem) {
1328
- selectItem(highlitedItem);
1329
- }
1330
- }
1331
- }
1332
- }),
1321
+ ...toggleButtonProps,
1333
1322
  after: /* @__PURE__ */ jsx(
1334
1323
  DropdownList,
1335
1324
  {
@@ -1345,11 +1334,7 @@ const Dropdown = React.forwardRef(
1345
1334
  noMatchesText,
1346
1335
  selectedItems: selectedItem !== null ? [selectedItem] : [],
1347
1336
  readOnly,
1348
- ...getMenuProps({
1349
- refKey: "innerRef",
1350
- ref: refs.setFloating,
1351
- style: listStyle
1352
- })
1337
+ ...menuProps
1353
1338
  }
1354
1339
  ),
1355
1340
  ...rest,