@radix-ui/react-select 2.3.8 → 2.3.9-rc.1791245332176

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.
package/dist/index.mjs CHANGED
@@ -24,7 +24,6 @@ import { createSlot } from "@radix-ui/react-slot";
24
24
  import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
25
25
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
26
26
  import { useLayoutEffect } from "@radix-ui/react-use-layout-effect";
27
- import { usePrevious } from "@radix-ui/react-use-previous";
28
27
  import { VISUALLY_HIDDEN_STYLES } from "@radix-ui/react-visually-hidden";
29
28
  import { hideOthers } from "aria-hidden";
30
29
  import { RemoveScroll } from "react-remove-scroll";
@@ -85,6 +84,11 @@ function SelectProvider(props) {
85
84
  caller: SELECT_NAME
86
85
  });
87
86
  const triggerPointerDownPosRef = React.useRef(null);
87
+ const hasConsumerStoppedPropagationRef = React.useRef(false);
88
+ const [userInteractionCount, onUserInteraction] = React.useReducer(
89
+ (count) => count + 1,
90
+ 0
91
+ );
88
92
  const initialValueRef = React.useRef(value);
89
93
  React.useEffect(() => {
90
94
  const associatedForm = form ? trigger?.ownerDocument.getElementById(form) : trigger?.form;
@@ -119,6 +123,9 @@ function SelectProvider(props) {
119
123
  contentId,
120
124
  value,
121
125
  onValueChange: setValue,
126
+ hasConsumerStoppedPropagationRef,
127
+ userInteractionCount,
128
+ onUserInteraction,
122
129
  open,
123
130
  onOpenChange: setOpen,
124
131
  dir: direction,
@@ -176,6 +183,7 @@ var SelectTrigger = /* @__PURE__ */ React.forwardRef(
176
183
  const currentItem = enabledItems.find((item) => item.value === context.value);
177
184
  const nextItem = findNextItem(enabledItems, search, currentItem);
178
185
  if (nextItem !== void 0) {
186
+ context.onUserInteraction();
179
187
  context.onValueChange(nextItem.value);
180
188
  }
181
189
  });
@@ -227,7 +235,10 @@ var SelectTrigger = /* @__PURE__ */ React.forwardRef(
227
235
  onKeyDown: composeEventHandlers(triggerProps.onKeyDown, (event) => {
228
236
  const isTypingAhead = searchRef.current !== "";
229
237
  const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
230
- if (!isModifierKey && event.key.length === 1) handleTypeaheadSearch(event.key);
238
+ if (!isModifierKey && event.key.length === 1) {
239
+ context.hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
240
+ handleTypeaheadSearch(event.key);
241
+ }
231
242
  if (isTypingAhead && event.key === " ") return;
232
243
  if (OPEN_KEYS.includes(event.key)) {
233
244
  handleOpen();
@@ -834,10 +845,13 @@ var SelectItem = /* @__PURE__ */ React.forwardRef(
834
845
  const composedRefs = useComposedRefs(forwardedRef, handleItemRefCallback);
835
846
  const textId = useId();
836
847
  const pointerTypeRef = React.useRef("touch");
837
- const handleSelect = /* @__PURE__ */ __name(() => {
848
+ function handleSelect(event) {
849
+ context.hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
850
+ context.onUserInteraction();
838
851
  context.onValueChange(value);
839
852
  context.onOpenChange(false);
840
- }, "handleSelect");
853
+ }
854
+ __name(handleSelect, "handleSelect");
841
855
  return /* @__PURE__ */ jsx(
842
856
  SelectItemContextProvider,
843
857
  {
@@ -871,20 +885,20 @@ var SelectItem = /* @__PURE__ */ React.forwardRef(
871
885
  ref: composedRefs,
872
886
  onFocus: composeEventHandlers(itemProps.onFocus, () => setIsFocused(true)),
873
887
  onBlur: composeEventHandlers(itemProps.onBlur, () => setIsFocused(false)),
874
- onClick: composeEventHandlers(itemProps.onClick, () => {
888
+ onClick: composeEventHandlers(itemProps.onClick, (event) => {
875
889
  if (disabled) {
876
890
  return;
877
891
  }
878
892
  if (pointerTypeRef.current !== "mouse") {
879
- handleSelect();
893
+ handleSelect(event);
880
894
  }
881
895
  }),
882
- onPointerUp: composeEventHandlers(itemProps.onPointerUp, () => {
896
+ onPointerUp: composeEventHandlers(itemProps.onPointerUp, (event) => {
883
897
  if (disabled) {
884
898
  return;
885
899
  }
886
900
  if (pointerTypeRef.current === "mouse") {
887
- handleSelect();
901
+ handleSelect(event);
888
902
  }
889
903
  }),
890
904
  onPointerDown: composeEventHandlers(itemProps.onPointerDown, (event) => {
@@ -912,7 +926,7 @@ var SelectItem = /* @__PURE__ */ React.forwardRef(
912
926
  return;
913
927
  }
914
928
  if (SELECTION_KEYS.includes(event.key)) {
915
- handleSelect();
929
+ handleSelect(event);
916
930
  }
917
931
  if (event.key === " ") {
918
932
  event.preventDefault();
@@ -1101,12 +1115,23 @@ var SelectBubbleInput = /* @__PURE__ */ React.forwardRef(
1101
1115
  // blank line to reduce diff noise
1102
1116
  /* @__PURE__ */ __name(function SelectBubbleInput2({ __scopeSelect, ...props }, forwardedRef) {
1103
1117
  const context = useSelectContext(BUBBLE_INPUT_NAME, __scopeSelect);
1104
- const { value, onValueChange, required, disabled, name, autoComplete, form } = context;
1118
+ const {
1119
+ value,
1120
+ onValueChange,
1121
+ required,
1122
+ disabled,
1123
+ name,
1124
+ autoComplete,
1125
+ form,
1126
+ hasConsumerStoppedPropagationRef,
1127
+ userInteractionCount
1128
+ } = context;
1105
1129
  const { nativeOptions, nativeSelectKey } = context;
1106
1130
  const ref = React.useRef(null);
1107
1131
  const composedRefs = useComposedRefs(forwardedRef, ref);
1108
1132
  const selectValue = value ?? "";
1109
- const prevValue = usePrevious(selectValue);
1133
+ const prevValueRef = React.useRef(selectValue);
1134
+ const prevUserInteractionCountRef = React.useRef(userInteractionCount);
1110
1135
  const hasEmptyValueOption = Array.from(nativeOptions).some(
1111
1136
  (option) => (option.props.value ?? "") === ""
1112
1137
  );
@@ -1119,12 +1144,17 @@ var SelectBubbleInput = /* @__PURE__ */ React.forwardRef(
1119
1144
  "value"
1120
1145
  );
1121
1146
  const setValue = descriptor.set;
1122
- if (prevValue !== selectValue && setValue) {
1123
- const event = new Event("change", { bubbles: true });
1147
+ const isUserInteraction = userInteractionCount !== prevUserInteractionCountRef.current;
1148
+ prevUserInteractionCountRef.current = userInteractionCount;
1149
+ const valueChanged = prevValueRef.current !== selectValue;
1150
+ prevValueRef.current = selectValue;
1151
+ const bubbles = isUserInteraction && !hasConsumerStoppedPropagationRef.current;
1152
+ if (valueChanged && setValue) {
1153
+ const event = new Event("change", { bubbles });
1124
1154
  setValue.call(select, selectValue);
1125
1155
  select.dispatchEvent(event);
1126
1156
  }
1127
- }, [prevValue, selectValue]);
1157
+ }, [hasConsumerStoppedPropagationRef, selectValue, userInteractionCount]);
1128
1158
  return /* @__PURE__ */ jsxs(
1129
1159
  Primitive.select,
1130
1160
  {
@@ -1165,11 +1195,13 @@ function useTypeaheadSearch(onSearchChange) {
1165
1195
  (key) => {
1166
1196
  const search = searchRef.current + key;
1167
1197
  handleSearchChange(search);
1168
- (/* @__PURE__ */ __name((function updateSearch(value) {
1198
+ function updateSearch(value) {
1169
1199
  searchRef.current = value;
1170
1200
  window.clearTimeout(timerRef.current);
1171
1201
  if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
1172
- }), "updateSearch"))(search);
1202
+ }
1203
+ __name(updateSearch, "updateSearch");
1204
+ updateSearch(search);
1173
1205
  },
1174
1206
  [handleSearchChange]
1175
1207
  );