@radix-ui/react-select 2.3.8 → 2.4.0-rc.1791406557805

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.d.mts CHANGED
@@ -18,30 +18,30 @@ declare const Direction: {
18
18
  };
19
19
  type Direction = (typeof Direction)[keyof typeof Direction];
20
20
  type ScopedProps<P> = P & {
21
- __scopeSelect?: Scope;
21
+ __scopeSelect?: Scope | undefined;
22
22
  };
23
23
  declare const createSelectScope: _radix_ui_react_context.CreateScope;
24
24
  interface SelectSharedProps {
25
- children?: React.ReactNode;
26
- open?: boolean;
27
- defaultOpen?: boolean;
28
- onOpenChange?(open: boolean): void;
29
- dir?: Direction;
30
- name?: string;
31
- autoComplete?: string;
32
- disabled?: boolean;
33
- required?: boolean;
34
- form?: string;
25
+ children?: React.ReactNode | undefined;
26
+ open?: boolean | undefined;
27
+ defaultOpen?: boolean | undefined;
28
+ onOpenChange?: ((open: boolean) => void) | undefined;
29
+ dir?: Direction | undefined;
30
+ name?: string | undefined;
31
+ autoComplete?: string | undefined;
32
+ disabled?: boolean | undefined;
33
+ required?: boolean | undefined;
34
+ form?: string | undefined;
35
35
  }
36
36
  type SelectProps = SelectSharedProps & {
37
- value?: string;
38
- defaultValue?: string;
39
- onValueChange?(value: string): void;
37
+ value?: string | undefined;
38
+ defaultValue?: string | undefined;
39
+ onValueChange?: ((value: string) => void) | undefined;
40
40
  };
41
41
  interface SelectProviderProps extends SelectSharedProps {
42
- value?: string;
43
- defaultValue?: string;
44
- onValueChange?(value: string): void;
42
+ value?: string | undefined;
43
+ defaultValue?: string | undefined;
44
+ onValueChange?: ((value: string) => void) | undefined;
45
45
  }
46
46
  declare function SelectProvider(props: ScopedProps<SelectProviderProps>): React.JSX.Element;
47
47
  declare const Select: React.FC<SelectProps>;
@@ -51,7 +51,7 @@ interface SelectTriggerProps extends PrimitiveButtonProps {
51
51
  declare const SelectTrigger: React.ForwardRefExoticComponent<SelectTriggerProps & React.RefAttributes<HTMLButtonElement>>;
52
52
  type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
53
53
  interface SelectValueProps extends Omit<PrimitiveSpanProps, 'placeholder'> {
54
- placeholder?: React.ReactNode;
54
+ placeholder?: React.ReactNode | undefined;
55
55
  }
56
56
  declare const SelectValue: React.ForwardRefExoticComponent<SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
57
57
  interface SelectIconProps extends PrimitiveSpanProps {
@@ -59,16 +59,16 @@ interface SelectIconProps extends PrimitiveSpanProps {
59
59
  declare const SelectIcon: React.ForwardRefExoticComponent<SelectIconProps & React.RefAttributes<HTMLSpanElement>>;
60
60
  type PortalProps = React.ComponentPropsWithoutRef<typeof Portal>;
61
61
  interface SelectPortalProps {
62
- children?: React.ReactNode;
62
+ children?: React.ReactNode | undefined;
63
63
  /**
64
64
  * Specify a container element to portal the content into.
65
65
  */
66
- container?: PortalProps['container'];
66
+ container?: PortalProps['container'] | undefined;
67
67
  /**
68
68
  * Used to force mounting when more control is needed. Useful when controlling
69
69
  * animation with React animation libraries.
70
70
  */
71
- forceMount?: true;
71
+ forceMount?: true | undefined;
72
72
  }
73
73
  declare const SelectPortal: React.FC<SelectPortalProps>;
74
74
  interface SelectContentProps extends SelectContentImplProps {
@@ -76,31 +76,31 @@ interface SelectContentProps extends SelectContentImplProps {
76
76
  * Used to force mounting when more control is needed. Useful when
77
77
  * controlling animation with React animation libraries.
78
78
  */
79
- forceMount?: true;
79
+ forceMount?: true | undefined;
80
80
  }
81
81
  declare const SelectContent: React.ForwardRefExoticComponent<SelectContentProps & React.RefAttributes<HTMLDivElement>>;
82
82
  type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
83
83
  type FocusScopeProps = React.ComponentPropsWithoutRef<typeof FocusScope>;
84
84
  type SelectPopperPrivateProps = {
85
- onPlaced?: PopperContentProps['onPlaced'];
85
+ onPlaced?: PopperContentProps['onPlaced'] | undefined;
86
86
  };
87
87
  interface SelectContentImplProps extends Omit<SelectPopperPositionProps, keyof SelectPopperPrivateProps>, Omit<SelectItemAlignedPositionProps, keyof SelectPopperPrivateProps> {
88
88
  /**
89
89
  * Event handler called when auto-focusing on close.
90
90
  * Can be prevented.
91
91
  */
92
- onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus'];
92
+ onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus'] | undefined;
93
93
  /**
94
94
  * Event handler called when the escape key is down.
95
95
  * Can be prevented.
96
96
  */
97
- onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
97
+ onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'] | undefined;
98
98
  /**
99
99
  * Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`.
100
100
  * Can be prevented.
101
101
  */
102
- onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
103
- position?: Position;
102
+ onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'] | undefined;
103
+ position?: Position | undefined;
104
104
  }
105
105
  interface SelectItemAlignedPositionProps extends PrimitiveDivProps, SelectPopperPrivateProps {
106
106
  }
@@ -109,7 +109,7 @@ interface SelectPopperPositionProps extends PopperContentProps, SelectPopperPriv
109
109
  }
110
110
  type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
111
111
  interface SelectViewportProps extends PrimitiveDivProps {
112
- nonce?: string;
112
+ nonce?: string | undefined;
113
113
  }
114
114
  declare const SelectViewport: React.ForwardRefExoticComponent<SelectViewportProps & React.RefAttributes<HTMLDivElement>>;
115
115
  interface SelectGroupProps extends PrimitiveDivProps {
@@ -120,8 +120,8 @@ interface SelectLabelProps extends PrimitiveDivProps {
120
120
  declare const SelectLabel: React.ForwardRefExoticComponent<SelectLabelProps & React.RefAttributes<HTMLDivElement>>;
121
121
  interface SelectItemProps extends PrimitiveDivProps {
122
122
  value: string;
123
- disabled?: boolean;
124
- textValue?: string;
123
+ disabled?: boolean | undefined;
124
+ textValue?: string | undefined;
125
125
  }
126
126
  declare const SelectItem: React.ForwardRefExoticComponent<SelectItemProps & React.RefAttributes<HTMLDivElement>>;
127
127
  interface SelectItemTextProps extends PrimitiveSpanProps {
package/dist/index.d.ts CHANGED
@@ -18,30 +18,30 @@ declare const Direction: {
18
18
  };
19
19
  type Direction = (typeof Direction)[keyof typeof Direction];
20
20
  type ScopedProps<P> = P & {
21
- __scopeSelect?: Scope;
21
+ __scopeSelect?: Scope | undefined;
22
22
  };
23
23
  declare const createSelectScope: _radix_ui_react_context.CreateScope;
24
24
  interface SelectSharedProps {
25
- children?: React.ReactNode;
26
- open?: boolean;
27
- defaultOpen?: boolean;
28
- onOpenChange?(open: boolean): void;
29
- dir?: Direction;
30
- name?: string;
31
- autoComplete?: string;
32
- disabled?: boolean;
33
- required?: boolean;
34
- form?: string;
25
+ children?: React.ReactNode | undefined;
26
+ open?: boolean | undefined;
27
+ defaultOpen?: boolean | undefined;
28
+ onOpenChange?: ((open: boolean) => void) | undefined;
29
+ dir?: Direction | undefined;
30
+ name?: string | undefined;
31
+ autoComplete?: string | undefined;
32
+ disabled?: boolean | undefined;
33
+ required?: boolean | undefined;
34
+ form?: string | undefined;
35
35
  }
36
36
  type SelectProps = SelectSharedProps & {
37
- value?: string;
38
- defaultValue?: string;
39
- onValueChange?(value: string): void;
37
+ value?: string | undefined;
38
+ defaultValue?: string | undefined;
39
+ onValueChange?: ((value: string) => void) | undefined;
40
40
  };
41
41
  interface SelectProviderProps extends SelectSharedProps {
42
- value?: string;
43
- defaultValue?: string;
44
- onValueChange?(value: string): void;
42
+ value?: string | undefined;
43
+ defaultValue?: string | undefined;
44
+ onValueChange?: ((value: string) => void) | undefined;
45
45
  }
46
46
  declare function SelectProvider(props: ScopedProps<SelectProviderProps>): React.JSX.Element;
47
47
  declare const Select: React.FC<SelectProps>;
@@ -51,7 +51,7 @@ interface SelectTriggerProps extends PrimitiveButtonProps {
51
51
  declare const SelectTrigger: React.ForwardRefExoticComponent<SelectTriggerProps & React.RefAttributes<HTMLButtonElement>>;
52
52
  type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
53
53
  interface SelectValueProps extends Omit<PrimitiveSpanProps, 'placeholder'> {
54
- placeholder?: React.ReactNode;
54
+ placeholder?: React.ReactNode | undefined;
55
55
  }
56
56
  declare const SelectValue: React.ForwardRefExoticComponent<SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
57
57
  interface SelectIconProps extends PrimitiveSpanProps {
@@ -59,16 +59,16 @@ interface SelectIconProps extends PrimitiveSpanProps {
59
59
  declare const SelectIcon: React.ForwardRefExoticComponent<SelectIconProps & React.RefAttributes<HTMLSpanElement>>;
60
60
  type PortalProps = React.ComponentPropsWithoutRef<typeof Portal>;
61
61
  interface SelectPortalProps {
62
- children?: React.ReactNode;
62
+ children?: React.ReactNode | undefined;
63
63
  /**
64
64
  * Specify a container element to portal the content into.
65
65
  */
66
- container?: PortalProps['container'];
66
+ container?: PortalProps['container'] | undefined;
67
67
  /**
68
68
  * Used to force mounting when more control is needed. Useful when controlling
69
69
  * animation with React animation libraries.
70
70
  */
71
- forceMount?: true;
71
+ forceMount?: true | undefined;
72
72
  }
73
73
  declare const SelectPortal: React.FC<SelectPortalProps>;
74
74
  interface SelectContentProps extends SelectContentImplProps {
@@ -76,31 +76,31 @@ interface SelectContentProps extends SelectContentImplProps {
76
76
  * Used to force mounting when more control is needed. Useful when
77
77
  * controlling animation with React animation libraries.
78
78
  */
79
- forceMount?: true;
79
+ forceMount?: true | undefined;
80
80
  }
81
81
  declare const SelectContent: React.ForwardRefExoticComponent<SelectContentProps & React.RefAttributes<HTMLDivElement>>;
82
82
  type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
83
83
  type FocusScopeProps = React.ComponentPropsWithoutRef<typeof FocusScope>;
84
84
  type SelectPopperPrivateProps = {
85
- onPlaced?: PopperContentProps['onPlaced'];
85
+ onPlaced?: PopperContentProps['onPlaced'] | undefined;
86
86
  };
87
87
  interface SelectContentImplProps extends Omit<SelectPopperPositionProps, keyof SelectPopperPrivateProps>, Omit<SelectItemAlignedPositionProps, keyof SelectPopperPrivateProps> {
88
88
  /**
89
89
  * Event handler called when auto-focusing on close.
90
90
  * Can be prevented.
91
91
  */
92
- onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus'];
92
+ onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus'] | undefined;
93
93
  /**
94
94
  * Event handler called when the escape key is down.
95
95
  * Can be prevented.
96
96
  */
97
- onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
97
+ onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'] | undefined;
98
98
  /**
99
99
  * Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`.
100
100
  * Can be prevented.
101
101
  */
102
- onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
103
- position?: Position;
102
+ onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'] | undefined;
103
+ position?: Position | undefined;
104
104
  }
105
105
  interface SelectItemAlignedPositionProps extends PrimitiveDivProps, SelectPopperPrivateProps {
106
106
  }
@@ -109,7 +109,7 @@ interface SelectPopperPositionProps extends PopperContentProps, SelectPopperPriv
109
109
  }
110
110
  type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
111
111
  interface SelectViewportProps extends PrimitiveDivProps {
112
- nonce?: string;
112
+ nonce?: string | undefined;
113
113
  }
114
114
  declare const SelectViewport: React.ForwardRefExoticComponent<SelectViewportProps & React.RefAttributes<HTMLDivElement>>;
115
115
  interface SelectGroupProps extends PrimitiveDivProps {
@@ -120,8 +120,8 @@ interface SelectLabelProps extends PrimitiveDivProps {
120
120
  declare const SelectLabel: React.ForwardRefExoticComponent<SelectLabelProps & React.RefAttributes<HTMLDivElement>>;
121
121
  interface SelectItemProps extends PrimitiveDivProps {
122
122
  value: string;
123
- disabled?: boolean;
124
- textValue?: string;
123
+ disabled?: boolean | undefined;
124
+ textValue?: string | undefined;
125
125
  }
126
126
  declare const SelectItem: React.ForwardRefExoticComponent<SelectItemProps & React.RefAttributes<HTMLDivElement>>;
127
127
  interface SelectItemTextProps extends PrimitiveSpanProps {
package/dist/index.js CHANGED
@@ -94,7 +94,6 @@ var import_react_slot = require("@radix-ui/react-slot");
94
94
  var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
95
95
  var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state");
96
96
  var import_react_use_layout_effect = require("@radix-ui/react-use-layout-effect");
97
- var import_react_use_previous = require("@radix-ui/react-use-previous");
98
97
  var import_react_visually_hidden = require("@radix-ui/react-visually-hidden");
99
98
  var import_aria_hidden = require("aria-hidden");
100
99
  var import_react_remove_scroll = require("react-remove-scroll");
@@ -155,6 +154,11 @@ function SelectProvider(props) {
155
154
  caller: SELECT_NAME
156
155
  });
157
156
  const triggerPointerDownPosRef = React.useRef(null);
157
+ const hasConsumerStoppedPropagationRef = React.useRef(false);
158
+ const [userInteractionCount, onUserInteraction] = React.useReducer(
159
+ (count) => count + 1,
160
+ 0
161
+ );
158
162
  const initialValueRef = React.useRef(value);
159
163
  React.useEffect(() => {
160
164
  const associatedForm = form ? trigger?.ownerDocument.getElementById(form) : trigger?.form;
@@ -189,6 +193,9 @@ function SelectProvider(props) {
189
193
  contentId,
190
194
  value,
191
195
  onValueChange: setValue,
196
+ hasConsumerStoppedPropagationRef,
197
+ userInteractionCount,
198
+ onUserInteraction,
192
199
  open,
193
200
  onOpenChange: setOpen,
194
201
  dir: direction,
@@ -246,6 +253,7 @@ var SelectTrigger = /* @__PURE__ */ React.forwardRef(
246
253
  const currentItem = enabledItems.find((item) => item.value === context.value);
247
254
  const nextItem = findNextItem(enabledItems, search, currentItem);
248
255
  if (nextItem !== void 0) {
256
+ context.onUserInteraction();
249
257
  context.onValueChange(nextItem.value);
250
258
  }
251
259
  });
@@ -297,7 +305,10 @@ var SelectTrigger = /* @__PURE__ */ React.forwardRef(
297
305
  onKeyDown: (0, import_primitive.composeEventHandlers)(triggerProps.onKeyDown, (event) => {
298
306
  const isTypingAhead = searchRef.current !== "";
299
307
  const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
300
- if (!isModifierKey && event.key.length === 1) handleTypeaheadSearch(event.key);
308
+ if (!isModifierKey && event.key.length === 1) {
309
+ context.hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
310
+ handleTypeaheadSearch(event.key);
311
+ }
301
312
  if (isTypingAhead && event.key === " ") return;
302
313
  if (OPEN_KEYS.includes(event.key)) {
303
314
  handleOpen();
@@ -904,10 +915,13 @@ var SelectItem = /* @__PURE__ */ React.forwardRef(
904
915
  const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, handleItemRefCallback);
905
916
  const textId = (0, import_react_id.useId)();
906
917
  const pointerTypeRef = React.useRef("touch");
907
- const handleSelect = /* @__PURE__ */ __name(() => {
918
+ function handleSelect(event) {
919
+ context.hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
920
+ context.onUserInteraction();
908
921
  context.onValueChange(value);
909
922
  context.onOpenChange(false);
910
- }, "handleSelect");
923
+ }
924
+ __name(handleSelect, "handleSelect");
911
925
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
912
926
  SelectItemContextProvider,
913
927
  {
@@ -941,20 +955,20 @@ var SelectItem = /* @__PURE__ */ React.forwardRef(
941
955
  ref: composedRefs,
942
956
  onFocus: (0, import_primitive.composeEventHandlers)(itemProps.onFocus, () => setIsFocused(true)),
943
957
  onBlur: (0, import_primitive.composeEventHandlers)(itemProps.onBlur, () => setIsFocused(false)),
944
- onClick: (0, import_primitive.composeEventHandlers)(itemProps.onClick, () => {
958
+ onClick: (0, import_primitive.composeEventHandlers)(itemProps.onClick, (event) => {
945
959
  if (disabled) {
946
960
  return;
947
961
  }
948
962
  if (pointerTypeRef.current !== "mouse") {
949
- handleSelect();
963
+ handleSelect(event);
950
964
  }
951
965
  }),
952
- onPointerUp: (0, import_primitive.composeEventHandlers)(itemProps.onPointerUp, () => {
966
+ onPointerUp: (0, import_primitive.composeEventHandlers)(itemProps.onPointerUp, (event) => {
953
967
  if (disabled) {
954
968
  return;
955
969
  }
956
970
  if (pointerTypeRef.current === "mouse") {
957
- handleSelect();
971
+ handleSelect(event);
958
972
  }
959
973
  }),
960
974
  onPointerDown: (0, import_primitive.composeEventHandlers)(itemProps.onPointerDown, (event) => {
@@ -982,7 +996,7 @@ var SelectItem = /* @__PURE__ */ React.forwardRef(
982
996
  return;
983
997
  }
984
998
  if (SELECTION_KEYS.includes(event.key)) {
985
- handleSelect();
999
+ handleSelect(event);
986
1000
  }
987
1001
  if (event.key === " ") {
988
1002
  event.preventDefault();
@@ -1171,12 +1185,23 @@ var SelectBubbleInput = /* @__PURE__ */ React.forwardRef(
1171
1185
  // blank line to reduce diff noise
1172
1186
  /* @__PURE__ */ __name(function SelectBubbleInput2({ __scopeSelect, ...props }, forwardedRef) {
1173
1187
  const context = useSelectContext(BUBBLE_INPUT_NAME, __scopeSelect);
1174
- const { value, onValueChange, required, disabled, name, autoComplete, form } = context;
1188
+ const {
1189
+ value,
1190
+ onValueChange,
1191
+ required,
1192
+ disabled,
1193
+ name,
1194
+ autoComplete,
1195
+ form,
1196
+ hasConsumerStoppedPropagationRef,
1197
+ userInteractionCount
1198
+ } = context;
1175
1199
  const { nativeOptions, nativeSelectKey } = context;
1176
1200
  const ref = React.useRef(null);
1177
1201
  const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
1178
1202
  const selectValue = value ?? "";
1179
- const prevValue = (0, import_react_use_previous.usePrevious)(selectValue);
1203
+ const prevValueRef = React.useRef(selectValue);
1204
+ const prevUserInteractionCountRef = React.useRef(userInteractionCount);
1180
1205
  const hasEmptyValueOption = Array.from(nativeOptions).some(
1181
1206
  (option) => (option.props.value ?? "") === ""
1182
1207
  );
@@ -1189,12 +1214,17 @@ var SelectBubbleInput = /* @__PURE__ */ React.forwardRef(
1189
1214
  "value"
1190
1215
  );
1191
1216
  const setValue = descriptor.set;
1192
- if (prevValue !== selectValue && setValue) {
1193
- const event = new Event("change", { bubbles: true });
1217
+ const isUserInteraction = userInteractionCount !== prevUserInteractionCountRef.current;
1218
+ prevUserInteractionCountRef.current = userInteractionCount;
1219
+ const valueChanged = prevValueRef.current !== selectValue;
1220
+ prevValueRef.current = selectValue;
1221
+ const bubbles = isUserInteraction && !hasConsumerStoppedPropagationRef.current;
1222
+ if (valueChanged && setValue) {
1223
+ const event = new Event("change", { bubbles });
1194
1224
  setValue.call(select, selectValue);
1195
1225
  select.dispatchEvent(event);
1196
1226
  }
1197
- }, [prevValue, selectValue]);
1227
+ }, [hasConsumerStoppedPropagationRef, selectValue, userInteractionCount]);
1198
1228
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1199
1229
  import_react_primitive.Primitive.select,
1200
1230
  {
@@ -1235,11 +1265,13 @@ function useTypeaheadSearch(onSearchChange) {
1235
1265
  (key) => {
1236
1266
  const search = searchRef.current + key;
1237
1267
  handleSearchChange(search);
1238
- (/* @__PURE__ */ __name((function updateSearch(value) {
1268
+ function updateSearch(value) {
1239
1269
  searchRef.current = value;
1240
1270
  window.clearTimeout(timerRef.current);
1241
1271
  if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
1242
- }), "updateSearch"))(search);
1272
+ }
1273
+ __name(updateSearch, "updateSearch");
1274
+ updateSearch(search);
1243
1275
  },
1244
1276
  [handleSearchChange]
1245
1277
  );