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