@seed-design/react-menu 1.0.0 → 2.0.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.
@@ -7,7 +7,7 @@ import { DismissibleLayer } from '@seed-design/react-dismissible-layer';
7
7
  import { mergeProps } from '@seed-design/dom-utils';
8
8
  import { Primitive } from '@seed-design/react-primitive';
9
9
  import React, { createContext, useContext, forwardRef } from 'react';
10
- import { u as useMenu } from './useMenu-12s-BrOJabEO.js';
10
+ import { u as useMenuGroup, a as useMenu } from './useMenu-12s-a4Nmkf8N.js';
11
11
 
12
12
  const MenuContext = /*#__PURE__*/ createContext(null);
13
13
  const MenuProvider = MenuContext.Provider;
@@ -29,7 +29,7 @@ function useMenuItemContext({ strict = true } = {}) {
29
29
  return context;
30
30
  }
31
31
 
32
- const MenuGroupLabelIdContext = /*#__PURE__*/ createContext(null);
32
+ const MenuGroupContext = /*#__PURE__*/ createContext(null);
33
33
  const MenuRoot = ({ open, defaultOpen, onOpenChange, disabled, placement, gutter, overflowPadding, strategy, matchReferenceWidth, children })=>{
34
34
  const api = useMenu({
35
35
  open,
@@ -164,24 +164,24 @@ const MenuItem = /*#__PURE__*/ forwardRef(({ disabled, typeaheadLabel, onClick,
164
164
  });
165
165
  MenuItem.displayName = "MenuItem";
166
166
  const MenuGroup = /*#__PURE__*/ forwardRef((props, ref)=>{
167
- const { getGroupProps } = useMenuContext();
168
- const { labelId, rootProps } = getGroupProps();
169
- return /*#__PURE__*/ jsx(MenuGroupLabelIdContext.Provider, {
170
- value: labelId,
167
+ const group = useMenuGroup();
168
+ return /*#__PURE__*/ jsx(MenuGroupContext.Provider, {
169
+ value: group,
171
170
  children: /*#__PURE__*/ jsx(Primitive.div, {
172
171
  ref: ref,
173
- ...mergeProps(rootProps, props)
172
+ ...mergeProps(group.rootProps, props)
174
173
  })
175
174
  });
176
175
  });
177
176
  MenuGroup.displayName = "MenuGroup";
178
177
  const MenuGroupLabel = /*#__PURE__*/ forwardRef((props, ref)=>{
179
- const { getGroupLabelProps } = useMenuContext();
180
- const labelId = React.useContext(MenuGroupLabelIdContext);
181
- if (!labelId) throw new Error("MenuGroupLabel must be used within a MenuGroup");
178
+ const group = React.useContext(MenuGroupContext);
179
+ if (!group) throw new Error("MenuGroupLabel must be used within a MenuGroup");
180
+ // Compose the group's label ref so the group advertises aria-labelledby only
181
+ // while this label is actually rendered (see useMenuGroup).
182
182
  return /*#__PURE__*/ jsx(Primitive.div, {
183
- ref: ref,
184
- ...mergeProps(getGroupLabelProps(labelId), props)
183
+ ref: composeRefs(group.refs.label, ref),
184
+ ...mergeProps(group.labelProps, props)
185
185
  });
186
186
  });
187
187
  MenuGroupLabel.displayName = "MenuGroupLabel";
@@ -7,7 +7,7 @@ var reactDismissibleLayer = require('@seed-design/react-dismissible-layer');
7
7
  var domUtils = require('@seed-design/dom-utils');
8
8
  var reactPrimitive = require('@seed-design/react-primitive');
9
9
  var React = require('react');
10
- var useMenu12s = require('./useMenu-12s-Cv5FQJ3x.cjs');
10
+ var useMenu12s = require('./useMenu-12s-B5iYt8f4.cjs');
11
11
 
12
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
13
 
@@ -33,7 +33,7 @@ function useMenuItemContext({ strict = true } = {}) {
33
33
  return context;
34
34
  }
35
35
 
36
- const MenuGroupLabelIdContext = /*#__PURE__*/ React.createContext(null);
36
+ const MenuGroupContext = /*#__PURE__*/ React.createContext(null);
37
37
  const MenuRoot = ({ open, defaultOpen, onOpenChange, disabled, placement, gutter, overflowPadding, strategy, matchReferenceWidth, children })=>{
38
38
  const api = useMenu12s.useMenu({
39
39
  open,
@@ -168,24 +168,24 @@ const MenuItem = /*#__PURE__*/ React.forwardRef(({ disabled, typeaheadLabel, onC
168
168
  });
169
169
  MenuItem.displayName = "MenuItem";
170
170
  const MenuGroup = /*#__PURE__*/ React.forwardRef((props, ref)=>{
171
- const { getGroupProps } = useMenuContext();
172
- const { labelId, rootProps } = getGroupProps();
173
- return /*#__PURE__*/ jsxRuntime.jsx(MenuGroupLabelIdContext.Provider, {
174
- value: labelId,
171
+ const group = useMenu12s.useMenuGroup();
172
+ return /*#__PURE__*/ jsxRuntime.jsx(MenuGroupContext.Provider, {
173
+ value: group,
175
174
  children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
176
175
  ref: ref,
177
- ...domUtils.mergeProps(rootProps, props)
176
+ ...domUtils.mergeProps(group.rootProps, props)
178
177
  })
179
178
  });
180
179
  });
181
180
  MenuGroup.displayName = "MenuGroup";
182
181
  const MenuGroupLabel = /*#__PURE__*/ React.forwardRef((props, ref)=>{
183
- const { getGroupLabelProps } = useMenuContext();
184
- const labelId = React__default.default.useContext(MenuGroupLabelIdContext);
185
- if (!labelId) throw new Error("MenuGroupLabel must be used within a MenuGroup");
182
+ const group = React__default.default.useContext(MenuGroupContext);
183
+ if (!group) throw new Error("MenuGroupLabel must be used within a MenuGroup");
184
+ // Compose the group's label ref so the group advertises aria-labelledby only
185
+ // while this label is actually rendered (see useMenuGroup).
186
186
  return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
187
- ref: ref,
188
- ...domUtils.mergeProps(getGroupLabelProps(labelId), props)
187
+ ref: reactComposeRefs.composeRefs(group.refs.label, ref),
188
+ ...domUtils.mergeProps(group.labelProps, props)
189
189
  });
190
190
  });
191
191
  MenuGroupLabel.displayName = "MenuGroupLabel";
package/lib/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- var Menu12s = require('./Menu-12s-BZEIsPP0.cjs');
1
+ var Menu12s = require('./Menu-12s-RqWENzzc.cjs');
2
2
 
3
3
  var Menu_namespace = {
4
4
  __proto__: null,
package/lib/index.d.ts CHANGED
@@ -2090,573 +2090,6 @@ declare function useMenu(props: UseMenuProps): {
2090
2090
  onTransitionStartCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2091
2091
  };
2092
2092
  };
2093
- getGroupProps: () => {
2094
- labelId: string;
2095
- rootProps: {
2096
- children?: react.ReactNode;
2097
- defaultChecked?: boolean | undefined | undefined;
2098
- defaultValue?: string | number | readonly string[] | undefined;
2099
- suppressContentEditableWarning?: boolean | undefined | undefined;
2100
- suppressHydrationWarning?: boolean | undefined | undefined;
2101
- accessKey?: string | undefined | undefined;
2102
- autoCapitalize?: "off" | "none" | "on" | "sentences" | "words" | "characters" | undefined | (string & {}) | undefined;
2103
- autoFocus?: boolean | undefined | undefined;
2104
- className?: string | undefined | undefined;
2105
- contentEditable?: (boolean | "false" | "true") | "inherit" | "plaintext-only" | undefined;
2106
- contextMenu?: string | undefined | undefined;
2107
- dir?: string | undefined | undefined;
2108
- draggable?: (boolean | "false" | "true") | undefined;
2109
- enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
2110
- hidden?: boolean | undefined | undefined;
2111
- id?: string | undefined | undefined;
2112
- lang?: string | undefined | undefined;
2113
- nonce?: string | undefined | undefined;
2114
- slot?: string | undefined | undefined;
2115
- spellCheck?: (boolean | "false" | "true") | undefined;
2116
- style?: react.CSSProperties | undefined;
2117
- tabIndex?: number | undefined | undefined;
2118
- title?: string | undefined | undefined;
2119
- translate?: "yes" | "no" | undefined | undefined;
2120
- radioGroup?: string | undefined | undefined;
2121
- role?: react.AriaRole | undefined;
2122
- about?: string | undefined | undefined;
2123
- content?: string | undefined | undefined;
2124
- datatype?: string | undefined | undefined;
2125
- inlist?: any;
2126
- prefix?: string | undefined | undefined;
2127
- property?: string | undefined | undefined;
2128
- rel?: string | undefined | undefined;
2129
- resource?: string | undefined | undefined;
2130
- rev?: string | undefined | undefined;
2131
- typeof?: string | undefined | undefined;
2132
- vocab?: string | undefined | undefined;
2133
- autoCorrect?: string | undefined | undefined;
2134
- autoSave?: string | undefined | undefined;
2135
- color?: string | undefined | undefined;
2136
- itemProp?: string | undefined | undefined;
2137
- itemScope?: boolean | undefined | undefined;
2138
- itemType?: string | undefined | undefined;
2139
- itemID?: string | undefined | undefined;
2140
- itemRef?: string | undefined | undefined;
2141
- results?: number | undefined | undefined;
2142
- security?: string | undefined | undefined;
2143
- unselectable?: "on" | "off" | undefined | undefined;
2144
- popover?: "" | "auto" | "manual" | "hint" | undefined | undefined;
2145
- popoverTargetAction?: "toggle" | "show" | "hide" | undefined | undefined;
2146
- popoverTarget?: string | undefined | undefined;
2147
- inert?: boolean | undefined | undefined;
2148
- inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
2149
- is?: string | undefined | undefined;
2150
- exportparts?: string | undefined | undefined;
2151
- part?: string | undefined | undefined;
2152
- "aria-activedescendant"?: string | undefined | undefined;
2153
- "aria-atomic"?: (boolean | "false" | "true") | undefined;
2154
- "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
2155
- "aria-braillelabel"?: string | undefined | undefined;
2156
- "aria-brailleroledescription"?: string | undefined | undefined;
2157
- "aria-busy"?: (boolean | "false" | "true") | undefined;
2158
- "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
2159
- "aria-colcount"?: number | undefined | undefined;
2160
- "aria-colindex"?: number | undefined | undefined;
2161
- "aria-colindextext"?: string | undefined | undefined;
2162
- "aria-colspan"?: number | undefined | undefined;
2163
- "aria-controls"?: string | undefined | undefined;
2164
- "aria-current"?: boolean | "false" | "true" | "page" | "step" | "location" | "date" | "time" | undefined | undefined;
2165
- "aria-describedby"?: string | undefined | undefined;
2166
- "aria-description"?: string | undefined | undefined;
2167
- "aria-details"?: string | undefined | undefined;
2168
- "aria-disabled"?: (boolean | "false" | "true") | undefined;
2169
- "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined | undefined;
2170
- "aria-errormessage"?: string | undefined | undefined;
2171
- "aria-expanded"?: (boolean | "false" | "true") | undefined;
2172
- "aria-flowto"?: string | undefined | undefined;
2173
- "aria-grabbed"?: (boolean | "false" | "true") | undefined;
2174
- "aria-haspopup"?: boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined | undefined;
2175
- "aria-hidden"?: (boolean | "false" | "true") | undefined;
2176
- "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined | undefined;
2177
- "aria-keyshortcuts"?: string | undefined | undefined;
2178
- "aria-label"?: string | undefined | undefined;
2179
- "aria-labelledby"?: string | undefined | undefined;
2180
- "aria-level"?: number | undefined | undefined;
2181
- "aria-live"?: "off" | "assertive" | "polite" | undefined | undefined;
2182
- "aria-modal"?: (boolean | "false" | "true") | undefined;
2183
- "aria-multiline"?: (boolean | "false" | "true") | undefined;
2184
- "aria-multiselectable"?: (boolean | "false" | "true") | undefined;
2185
- "aria-orientation"?: "horizontal" | "vertical" | undefined | undefined;
2186
- "aria-owns"?: string | undefined | undefined;
2187
- "aria-placeholder"?: string | undefined | undefined;
2188
- "aria-posinset"?: number | undefined | undefined;
2189
- "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
2190
- "aria-readonly"?: (boolean | "false" | "true") | undefined;
2191
- "aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined | undefined;
2192
- "aria-required"?: (boolean | "false" | "true") | undefined;
2193
- "aria-roledescription"?: string | undefined | undefined;
2194
- "aria-rowcount"?: number | undefined | undefined;
2195
- "aria-rowindex"?: number | undefined | undefined;
2196
- "aria-rowindextext"?: string | undefined | undefined;
2197
- "aria-rowspan"?: number | undefined | undefined;
2198
- "aria-selected"?: (boolean | "false" | "true") | undefined;
2199
- "aria-setsize"?: number | undefined | undefined;
2200
- "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined | undefined;
2201
- "aria-valuemax"?: number | undefined | undefined;
2202
- "aria-valuemin"?: number | undefined | undefined;
2203
- "aria-valuenow"?: number | undefined | undefined;
2204
- "aria-valuetext"?: string | undefined | undefined;
2205
- dangerouslySetInnerHTML?: {
2206
- __html: string | TrustedHTML;
2207
- } | undefined | undefined;
2208
- onCopy?: react.ClipboardEventHandler<HTMLElement> | undefined;
2209
- onCopyCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
2210
- onCut?: react.ClipboardEventHandler<HTMLElement> | undefined;
2211
- onCutCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
2212
- onPaste?: react.ClipboardEventHandler<HTMLElement> | undefined;
2213
- onPasteCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
2214
- onCompositionEnd?: react.CompositionEventHandler<HTMLElement> | undefined;
2215
- onCompositionEndCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
2216
- onCompositionStart?: react.CompositionEventHandler<HTMLElement> | undefined;
2217
- onCompositionStartCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
2218
- onCompositionUpdate?: react.CompositionEventHandler<HTMLElement> | undefined;
2219
- onCompositionUpdateCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
2220
- onFocus?: react.FocusEventHandler<HTMLElement> | undefined;
2221
- onFocusCapture?: react.FocusEventHandler<HTMLElement> | undefined;
2222
- onBlur?: react.FocusEventHandler<HTMLElement> | undefined;
2223
- onBlurCapture?: react.FocusEventHandler<HTMLElement> | undefined;
2224
- onChange?: react.FormEventHandler<HTMLElement> | undefined;
2225
- onChangeCapture?: react.FormEventHandler<HTMLElement> | undefined;
2226
- onBeforeInput?: react.InputEventHandler<HTMLElement> | undefined;
2227
- onBeforeInputCapture?: react.FormEventHandler<HTMLElement> | undefined;
2228
- onInput?: react.FormEventHandler<HTMLElement> | undefined;
2229
- onInputCapture?: react.FormEventHandler<HTMLElement> | undefined;
2230
- onReset?: react.FormEventHandler<HTMLElement> | undefined;
2231
- onResetCapture?: react.FormEventHandler<HTMLElement> | undefined;
2232
- onSubmit?: react.FormEventHandler<HTMLElement> | undefined;
2233
- onSubmitCapture?: react.FormEventHandler<HTMLElement> | undefined;
2234
- onInvalid?: react.FormEventHandler<HTMLElement> | undefined;
2235
- onInvalidCapture?: react.FormEventHandler<HTMLElement> | undefined;
2236
- onLoad?: react.ReactEventHandler<HTMLElement> | undefined;
2237
- onLoadCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2238
- onError?: react.ReactEventHandler<HTMLElement> | undefined;
2239
- onErrorCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2240
- onKeyDown?: react.KeyboardEventHandler<HTMLElement> | undefined;
2241
- onKeyDownCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
2242
- onKeyPress?: react.KeyboardEventHandler<HTMLElement> | undefined;
2243
- onKeyPressCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
2244
- onKeyUp?: react.KeyboardEventHandler<HTMLElement> | undefined;
2245
- onKeyUpCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
2246
- onAbort?: react.ReactEventHandler<HTMLElement> | undefined;
2247
- onAbortCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2248
- onCanPlay?: react.ReactEventHandler<HTMLElement> | undefined;
2249
- onCanPlayCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2250
- onCanPlayThrough?: react.ReactEventHandler<HTMLElement> | undefined;
2251
- onCanPlayThroughCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2252
- onDurationChange?: react.ReactEventHandler<HTMLElement> | undefined;
2253
- onDurationChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2254
- onEmptied?: react.ReactEventHandler<HTMLElement> | undefined;
2255
- onEmptiedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2256
- onEncrypted?: react.ReactEventHandler<HTMLElement> | undefined;
2257
- onEncryptedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2258
- onEnded?: react.ReactEventHandler<HTMLElement> | undefined;
2259
- onEndedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2260
- onLoadedData?: react.ReactEventHandler<HTMLElement> | undefined;
2261
- onLoadedDataCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2262
- onLoadedMetadata?: react.ReactEventHandler<HTMLElement> | undefined;
2263
- onLoadedMetadataCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2264
- onLoadStart?: react.ReactEventHandler<HTMLElement> | undefined;
2265
- onLoadStartCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2266
- onPause?: react.ReactEventHandler<HTMLElement> | undefined;
2267
- onPauseCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2268
- onPlay?: react.ReactEventHandler<HTMLElement> | undefined;
2269
- onPlayCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2270
- onPlaying?: react.ReactEventHandler<HTMLElement> | undefined;
2271
- onPlayingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2272
- onProgress?: react.ReactEventHandler<HTMLElement> | undefined;
2273
- onProgressCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2274
- onRateChange?: react.ReactEventHandler<HTMLElement> | undefined;
2275
- onRateChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2276
- onSeeked?: react.ReactEventHandler<HTMLElement> | undefined;
2277
- onSeekedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2278
- onSeeking?: react.ReactEventHandler<HTMLElement> | undefined;
2279
- onSeekingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2280
- onStalled?: react.ReactEventHandler<HTMLElement> | undefined;
2281
- onStalledCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2282
- onSuspend?: react.ReactEventHandler<HTMLElement> | undefined;
2283
- onSuspendCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2284
- onTimeUpdate?: react.ReactEventHandler<HTMLElement> | undefined;
2285
- onTimeUpdateCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2286
- onVolumeChange?: react.ReactEventHandler<HTMLElement> | undefined;
2287
- onVolumeChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2288
- onWaiting?: react.ReactEventHandler<HTMLElement> | undefined;
2289
- onWaitingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2290
- onAuxClick?: react.MouseEventHandler<HTMLElement> | undefined;
2291
- onAuxClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2292
- onClick?: react.MouseEventHandler<HTMLElement> | undefined;
2293
- onClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2294
- onContextMenu?: react.MouseEventHandler<HTMLElement> | undefined;
2295
- onContextMenuCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2296
- onDoubleClick?: react.MouseEventHandler<HTMLElement> | undefined;
2297
- onDoubleClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2298
- onDrag?: react.DragEventHandler<HTMLElement> | undefined;
2299
- onDragCapture?: react.DragEventHandler<HTMLElement> | undefined;
2300
- onDragEnd?: react.DragEventHandler<HTMLElement> | undefined;
2301
- onDragEndCapture?: react.DragEventHandler<HTMLElement> | undefined;
2302
- onDragEnter?: react.DragEventHandler<HTMLElement> | undefined;
2303
- onDragEnterCapture?: react.DragEventHandler<HTMLElement> | undefined;
2304
- onDragExit?: react.DragEventHandler<HTMLElement> | undefined;
2305
- onDragExitCapture?: react.DragEventHandler<HTMLElement> | undefined;
2306
- onDragLeave?: react.DragEventHandler<HTMLElement> | undefined;
2307
- onDragLeaveCapture?: react.DragEventHandler<HTMLElement> | undefined;
2308
- onDragOver?: react.DragEventHandler<HTMLElement> | undefined;
2309
- onDragOverCapture?: react.DragEventHandler<HTMLElement> | undefined;
2310
- onDragStart?: react.DragEventHandler<HTMLElement> | undefined;
2311
- onDragStartCapture?: react.DragEventHandler<HTMLElement> | undefined;
2312
- onDrop?: react.DragEventHandler<HTMLElement> | undefined;
2313
- onDropCapture?: react.DragEventHandler<HTMLElement> | undefined;
2314
- onMouseDown?: react.MouseEventHandler<HTMLElement> | undefined;
2315
- onMouseDownCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2316
- onMouseEnter?: react.MouseEventHandler<HTMLElement> | undefined;
2317
- onMouseLeave?: react.MouseEventHandler<HTMLElement> | undefined;
2318
- onMouseMove?: react.MouseEventHandler<HTMLElement> | undefined;
2319
- onMouseMoveCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2320
- onMouseOut?: react.MouseEventHandler<HTMLElement> | undefined;
2321
- onMouseOutCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2322
- onMouseOver?: react.MouseEventHandler<HTMLElement> | undefined;
2323
- onMouseOverCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2324
- onMouseUp?: react.MouseEventHandler<HTMLElement> | undefined;
2325
- onMouseUpCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2326
- onSelect?: react.ReactEventHandler<HTMLElement> | undefined;
2327
- onSelectCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2328
- onTouchCancel?: react.TouchEventHandler<HTMLElement> | undefined;
2329
- onTouchCancelCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2330
- onTouchEnd?: react.TouchEventHandler<HTMLElement> | undefined;
2331
- onTouchEndCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2332
- onTouchMove?: react.TouchEventHandler<HTMLElement> | undefined;
2333
- onTouchMoveCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2334
- onTouchStart?: react.TouchEventHandler<HTMLElement> | undefined;
2335
- onTouchStartCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2336
- onPointerDown?: react.PointerEventHandler<HTMLElement> | undefined;
2337
- onPointerDownCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2338
- onPointerMove?: react.PointerEventHandler<HTMLElement> | undefined;
2339
- onPointerMoveCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2340
- onPointerUp?: react.PointerEventHandler<HTMLElement> | undefined;
2341
- onPointerUpCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2342
- onPointerCancel?: react.PointerEventHandler<HTMLElement> | undefined;
2343
- onPointerCancelCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2344
- onPointerEnter?: react.PointerEventHandler<HTMLElement> | undefined;
2345
- onPointerLeave?: react.PointerEventHandler<HTMLElement> | undefined;
2346
- onPointerOver?: react.PointerEventHandler<HTMLElement> | undefined;
2347
- onPointerOverCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2348
- onPointerOut?: react.PointerEventHandler<HTMLElement> | undefined;
2349
- onPointerOutCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2350
- onGotPointerCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2351
- onGotPointerCaptureCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2352
- onLostPointerCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2353
- onLostPointerCaptureCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2354
- onScroll?: react.UIEventHandler<HTMLElement> | undefined;
2355
- onScrollCapture?: react.UIEventHandler<HTMLElement> | undefined;
2356
- onScrollEnd?: react.UIEventHandler<HTMLElement> | undefined;
2357
- onScrollEndCapture?: react.UIEventHandler<HTMLElement> | undefined;
2358
- onWheel?: react.WheelEventHandler<HTMLElement> | undefined;
2359
- onWheelCapture?: react.WheelEventHandler<HTMLElement> | undefined;
2360
- onAnimationStart?: react.AnimationEventHandler<HTMLElement> | undefined;
2361
- onAnimationStartCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
2362
- onAnimationEnd?: react.AnimationEventHandler<HTMLElement> | undefined;
2363
- onAnimationEndCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
2364
- onAnimationIteration?: react.AnimationEventHandler<HTMLElement> | undefined;
2365
- onAnimationIterationCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
2366
- onToggle?: react.ToggleEventHandler<HTMLElement> | undefined;
2367
- onBeforeToggle?: react.ToggleEventHandler<HTMLElement> | undefined;
2368
- onTransitionCancel?: react.TransitionEventHandler<HTMLElement> | undefined;
2369
- onTransitionCancelCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2370
- onTransitionEnd?: react.TransitionEventHandler<HTMLElement> | undefined;
2371
- onTransitionEndCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2372
- onTransitionRun?: react.TransitionEventHandler<HTMLElement> | undefined;
2373
- onTransitionRunCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2374
- onTransitionStart?: react.TransitionEventHandler<HTMLElement> | undefined;
2375
- onTransitionStartCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2376
- };
2377
- };
2378
- getGroupLabelProps: (labelId: string) => {
2379
- children?: react.ReactNode;
2380
- defaultChecked?: boolean | undefined | undefined;
2381
- defaultValue?: string | number | readonly string[] | undefined;
2382
- suppressContentEditableWarning?: boolean | undefined | undefined;
2383
- suppressHydrationWarning?: boolean | undefined | undefined;
2384
- accessKey?: string | undefined | undefined;
2385
- autoCapitalize?: "off" | "none" | "on" | "sentences" | "words" | "characters" | undefined | (string & {}) | undefined;
2386
- autoFocus?: boolean | undefined | undefined;
2387
- className?: string | undefined | undefined;
2388
- contentEditable?: (boolean | "false" | "true") | "inherit" | "plaintext-only" | undefined;
2389
- contextMenu?: string | undefined | undefined;
2390
- dir?: string | undefined | undefined;
2391
- draggable?: (boolean | "false" | "true") | undefined;
2392
- enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
2393
- hidden?: boolean | undefined | undefined;
2394
- id?: string | undefined | undefined;
2395
- lang?: string | undefined | undefined;
2396
- nonce?: string | undefined | undefined;
2397
- slot?: string | undefined | undefined;
2398
- spellCheck?: (boolean | "false" | "true") | undefined;
2399
- style?: react.CSSProperties | undefined;
2400
- tabIndex?: number | undefined | undefined;
2401
- title?: string | undefined | undefined;
2402
- translate?: "yes" | "no" | undefined | undefined;
2403
- radioGroup?: string | undefined | undefined;
2404
- role?: react.AriaRole | undefined;
2405
- about?: string | undefined | undefined;
2406
- content?: string | undefined | undefined;
2407
- datatype?: string | undefined | undefined;
2408
- inlist?: any;
2409
- prefix?: string | undefined | undefined;
2410
- property?: string | undefined | undefined;
2411
- rel?: string | undefined | undefined;
2412
- resource?: string | undefined | undefined;
2413
- rev?: string | undefined | undefined;
2414
- typeof?: string | undefined | undefined;
2415
- vocab?: string | undefined | undefined;
2416
- autoCorrect?: string | undefined | undefined;
2417
- autoSave?: string | undefined | undefined;
2418
- color?: string | undefined | undefined;
2419
- itemProp?: string | undefined | undefined;
2420
- itemScope?: boolean | undefined | undefined;
2421
- itemType?: string | undefined | undefined;
2422
- itemID?: string | undefined | undefined;
2423
- itemRef?: string | undefined | undefined;
2424
- results?: number | undefined | undefined;
2425
- security?: string | undefined | undefined;
2426
- unselectable?: "on" | "off" | undefined | undefined;
2427
- popover?: "" | "auto" | "manual" | "hint" | undefined | undefined;
2428
- popoverTargetAction?: "toggle" | "show" | "hide" | undefined | undefined;
2429
- popoverTarget?: string | undefined | undefined;
2430
- inert?: boolean | undefined | undefined;
2431
- inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
2432
- is?: string | undefined | undefined;
2433
- exportparts?: string | undefined | undefined;
2434
- part?: string | undefined | undefined;
2435
- "aria-activedescendant"?: string | undefined | undefined;
2436
- "aria-atomic"?: (boolean | "false" | "true") | undefined;
2437
- "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
2438
- "aria-braillelabel"?: string | undefined | undefined;
2439
- "aria-brailleroledescription"?: string | undefined | undefined;
2440
- "aria-busy"?: (boolean | "false" | "true") | undefined;
2441
- "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
2442
- "aria-colcount"?: number | undefined | undefined;
2443
- "aria-colindex"?: number | undefined | undefined;
2444
- "aria-colindextext"?: string | undefined | undefined;
2445
- "aria-colspan"?: number | undefined | undefined;
2446
- "aria-controls"?: string | undefined | undefined;
2447
- "aria-current"?: boolean | "false" | "true" | "page" | "step" | "location" | "date" | "time" | undefined | undefined;
2448
- "aria-describedby"?: string | undefined | undefined;
2449
- "aria-description"?: string | undefined | undefined;
2450
- "aria-details"?: string | undefined | undefined;
2451
- "aria-disabled"?: (boolean | "false" | "true") | undefined;
2452
- "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined | undefined;
2453
- "aria-errormessage"?: string | undefined | undefined;
2454
- "aria-expanded"?: (boolean | "false" | "true") | undefined;
2455
- "aria-flowto"?: string | undefined | undefined;
2456
- "aria-grabbed"?: (boolean | "false" | "true") | undefined;
2457
- "aria-haspopup"?: boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined | undefined;
2458
- "aria-hidden"?: (boolean | "false" | "true") | undefined;
2459
- "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined | undefined;
2460
- "aria-keyshortcuts"?: string | undefined | undefined;
2461
- "aria-label"?: string | undefined | undefined;
2462
- "aria-labelledby"?: string | undefined | undefined;
2463
- "aria-level"?: number | undefined | undefined;
2464
- "aria-live"?: "off" | "assertive" | "polite" | undefined | undefined;
2465
- "aria-modal"?: (boolean | "false" | "true") | undefined;
2466
- "aria-multiline"?: (boolean | "false" | "true") | undefined;
2467
- "aria-multiselectable"?: (boolean | "false" | "true") | undefined;
2468
- "aria-orientation"?: "horizontal" | "vertical" | undefined | undefined;
2469
- "aria-owns"?: string | undefined | undefined;
2470
- "aria-placeholder"?: string | undefined | undefined;
2471
- "aria-posinset"?: number | undefined | undefined;
2472
- "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
2473
- "aria-readonly"?: (boolean | "false" | "true") | undefined;
2474
- "aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined | undefined;
2475
- "aria-required"?: (boolean | "false" | "true") | undefined;
2476
- "aria-roledescription"?: string | undefined | undefined;
2477
- "aria-rowcount"?: number | undefined | undefined;
2478
- "aria-rowindex"?: number | undefined | undefined;
2479
- "aria-rowindextext"?: string | undefined | undefined;
2480
- "aria-rowspan"?: number | undefined | undefined;
2481
- "aria-selected"?: (boolean | "false" | "true") | undefined;
2482
- "aria-setsize"?: number | undefined | undefined;
2483
- "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined | undefined;
2484
- "aria-valuemax"?: number | undefined | undefined;
2485
- "aria-valuemin"?: number | undefined | undefined;
2486
- "aria-valuenow"?: number | undefined | undefined;
2487
- "aria-valuetext"?: string | undefined | undefined;
2488
- dangerouslySetInnerHTML?: {
2489
- __html: string | TrustedHTML;
2490
- } | undefined | undefined;
2491
- onCopy?: react.ClipboardEventHandler<HTMLElement> | undefined;
2492
- onCopyCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
2493
- onCut?: react.ClipboardEventHandler<HTMLElement> | undefined;
2494
- onCutCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
2495
- onPaste?: react.ClipboardEventHandler<HTMLElement> | undefined;
2496
- onPasteCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
2497
- onCompositionEnd?: react.CompositionEventHandler<HTMLElement> | undefined;
2498
- onCompositionEndCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
2499
- onCompositionStart?: react.CompositionEventHandler<HTMLElement> | undefined;
2500
- onCompositionStartCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
2501
- onCompositionUpdate?: react.CompositionEventHandler<HTMLElement> | undefined;
2502
- onCompositionUpdateCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
2503
- onFocus?: react.FocusEventHandler<HTMLElement> | undefined;
2504
- onFocusCapture?: react.FocusEventHandler<HTMLElement> | undefined;
2505
- onBlur?: react.FocusEventHandler<HTMLElement> | undefined;
2506
- onBlurCapture?: react.FocusEventHandler<HTMLElement> | undefined;
2507
- onChange?: react.FormEventHandler<HTMLElement> | undefined;
2508
- onChangeCapture?: react.FormEventHandler<HTMLElement> | undefined;
2509
- onBeforeInput?: react.InputEventHandler<HTMLElement> | undefined;
2510
- onBeforeInputCapture?: react.FormEventHandler<HTMLElement> | undefined;
2511
- onInput?: react.FormEventHandler<HTMLElement> | undefined;
2512
- onInputCapture?: react.FormEventHandler<HTMLElement> | undefined;
2513
- onReset?: react.FormEventHandler<HTMLElement> | undefined;
2514
- onResetCapture?: react.FormEventHandler<HTMLElement> | undefined;
2515
- onSubmit?: react.FormEventHandler<HTMLElement> | undefined;
2516
- onSubmitCapture?: react.FormEventHandler<HTMLElement> | undefined;
2517
- onInvalid?: react.FormEventHandler<HTMLElement> | undefined;
2518
- onInvalidCapture?: react.FormEventHandler<HTMLElement> | undefined;
2519
- onLoad?: react.ReactEventHandler<HTMLElement> | undefined;
2520
- onLoadCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2521
- onError?: react.ReactEventHandler<HTMLElement> | undefined;
2522
- onErrorCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2523
- onKeyDown?: react.KeyboardEventHandler<HTMLElement> | undefined;
2524
- onKeyDownCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
2525
- onKeyPress?: react.KeyboardEventHandler<HTMLElement> | undefined;
2526
- onKeyPressCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
2527
- onKeyUp?: react.KeyboardEventHandler<HTMLElement> | undefined;
2528
- onKeyUpCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
2529
- onAbort?: react.ReactEventHandler<HTMLElement> | undefined;
2530
- onAbortCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2531
- onCanPlay?: react.ReactEventHandler<HTMLElement> | undefined;
2532
- onCanPlayCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2533
- onCanPlayThrough?: react.ReactEventHandler<HTMLElement> | undefined;
2534
- onCanPlayThroughCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2535
- onDurationChange?: react.ReactEventHandler<HTMLElement> | undefined;
2536
- onDurationChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2537
- onEmptied?: react.ReactEventHandler<HTMLElement> | undefined;
2538
- onEmptiedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2539
- onEncrypted?: react.ReactEventHandler<HTMLElement> | undefined;
2540
- onEncryptedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2541
- onEnded?: react.ReactEventHandler<HTMLElement> | undefined;
2542
- onEndedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2543
- onLoadedData?: react.ReactEventHandler<HTMLElement> | undefined;
2544
- onLoadedDataCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2545
- onLoadedMetadata?: react.ReactEventHandler<HTMLElement> | undefined;
2546
- onLoadedMetadataCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2547
- onLoadStart?: react.ReactEventHandler<HTMLElement> | undefined;
2548
- onLoadStartCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2549
- onPause?: react.ReactEventHandler<HTMLElement> | undefined;
2550
- onPauseCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2551
- onPlay?: react.ReactEventHandler<HTMLElement> | undefined;
2552
- onPlayCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2553
- onPlaying?: react.ReactEventHandler<HTMLElement> | undefined;
2554
- onPlayingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2555
- onProgress?: react.ReactEventHandler<HTMLElement> | undefined;
2556
- onProgressCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2557
- onRateChange?: react.ReactEventHandler<HTMLElement> | undefined;
2558
- onRateChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2559
- onSeeked?: react.ReactEventHandler<HTMLElement> | undefined;
2560
- onSeekedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2561
- onSeeking?: react.ReactEventHandler<HTMLElement> | undefined;
2562
- onSeekingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2563
- onStalled?: react.ReactEventHandler<HTMLElement> | undefined;
2564
- onStalledCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2565
- onSuspend?: react.ReactEventHandler<HTMLElement> | undefined;
2566
- onSuspendCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2567
- onTimeUpdate?: react.ReactEventHandler<HTMLElement> | undefined;
2568
- onTimeUpdateCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2569
- onVolumeChange?: react.ReactEventHandler<HTMLElement> | undefined;
2570
- onVolumeChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2571
- onWaiting?: react.ReactEventHandler<HTMLElement> | undefined;
2572
- onWaitingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2573
- onAuxClick?: react.MouseEventHandler<HTMLElement> | undefined;
2574
- onAuxClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2575
- onClick?: react.MouseEventHandler<HTMLElement> | undefined;
2576
- onClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2577
- onContextMenu?: react.MouseEventHandler<HTMLElement> | undefined;
2578
- onContextMenuCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2579
- onDoubleClick?: react.MouseEventHandler<HTMLElement> | undefined;
2580
- onDoubleClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2581
- onDrag?: react.DragEventHandler<HTMLElement> | undefined;
2582
- onDragCapture?: react.DragEventHandler<HTMLElement> | undefined;
2583
- onDragEnd?: react.DragEventHandler<HTMLElement> | undefined;
2584
- onDragEndCapture?: react.DragEventHandler<HTMLElement> | undefined;
2585
- onDragEnter?: react.DragEventHandler<HTMLElement> | undefined;
2586
- onDragEnterCapture?: react.DragEventHandler<HTMLElement> | undefined;
2587
- onDragExit?: react.DragEventHandler<HTMLElement> | undefined;
2588
- onDragExitCapture?: react.DragEventHandler<HTMLElement> | undefined;
2589
- onDragLeave?: react.DragEventHandler<HTMLElement> | undefined;
2590
- onDragLeaveCapture?: react.DragEventHandler<HTMLElement> | undefined;
2591
- onDragOver?: react.DragEventHandler<HTMLElement> | undefined;
2592
- onDragOverCapture?: react.DragEventHandler<HTMLElement> | undefined;
2593
- onDragStart?: react.DragEventHandler<HTMLElement> | undefined;
2594
- onDragStartCapture?: react.DragEventHandler<HTMLElement> | undefined;
2595
- onDrop?: react.DragEventHandler<HTMLElement> | undefined;
2596
- onDropCapture?: react.DragEventHandler<HTMLElement> | undefined;
2597
- onMouseDown?: react.MouseEventHandler<HTMLElement> | undefined;
2598
- onMouseDownCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2599
- onMouseEnter?: react.MouseEventHandler<HTMLElement> | undefined;
2600
- onMouseLeave?: react.MouseEventHandler<HTMLElement> | undefined;
2601
- onMouseMove?: react.MouseEventHandler<HTMLElement> | undefined;
2602
- onMouseMoveCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2603
- onMouseOut?: react.MouseEventHandler<HTMLElement> | undefined;
2604
- onMouseOutCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2605
- onMouseOver?: react.MouseEventHandler<HTMLElement> | undefined;
2606
- onMouseOverCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2607
- onMouseUp?: react.MouseEventHandler<HTMLElement> | undefined;
2608
- onMouseUpCapture?: react.MouseEventHandler<HTMLElement> | undefined;
2609
- onSelect?: react.ReactEventHandler<HTMLElement> | undefined;
2610
- onSelectCapture?: react.ReactEventHandler<HTMLElement> | undefined;
2611
- onTouchCancel?: react.TouchEventHandler<HTMLElement> | undefined;
2612
- onTouchCancelCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2613
- onTouchEnd?: react.TouchEventHandler<HTMLElement> | undefined;
2614
- onTouchEndCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2615
- onTouchMove?: react.TouchEventHandler<HTMLElement> | undefined;
2616
- onTouchMoveCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2617
- onTouchStart?: react.TouchEventHandler<HTMLElement> | undefined;
2618
- onTouchStartCapture?: react.TouchEventHandler<HTMLElement> | undefined;
2619
- onPointerDown?: react.PointerEventHandler<HTMLElement> | undefined;
2620
- onPointerDownCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2621
- onPointerMove?: react.PointerEventHandler<HTMLElement> | undefined;
2622
- onPointerMoveCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2623
- onPointerUp?: react.PointerEventHandler<HTMLElement> | undefined;
2624
- onPointerUpCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2625
- onPointerCancel?: react.PointerEventHandler<HTMLElement> | undefined;
2626
- onPointerCancelCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2627
- onPointerEnter?: react.PointerEventHandler<HTMLElement> | undefined;
2628
- onPointerLeave?: react.PointerEventHandler<HTMLElement> | undefined;
2629
- onPointerOver?: react.PointerEventHandler<HTMLElement> | undefined;
2630
- onPointerOverCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2631
- onPointerOut?: react.PointerEventHandler<HTMLElement> | undefined;
2632
- onPointerOutCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2633
- onGotPointerCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2634
- onGotPointerCaptureCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2635
- onLostPointerCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2636
- onLostPointerCaptureCapture?: react.PointerEventHandler<HTMLElement> | undefined;
2637
- onScroll?: react.UIEventHandler<HTMLElement> | undefined;
2638
- onScrollCapture?: react.UIEventHandler<HTMLElement> | undefined;
2639
- onScrollEnd?: react.UIEventHandler<HTMLElement> | undefined;
2640
- onScrollEndCapture?: react.UIEventHandler<HTMLElement> | undefined;
2641
- onWheel?: react.WheelEventHandler<HTMLElement> | undefined;
2642
- onWheelCapture?: react.WheelEventHandler<HTMLElement> | undefined;
2643
- onAnimationStart?: react.AnimationEventHandler<HTMLElement> | undefined;
2644
- onAnimationStartCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
2645
- onAnimationEnd?: react.AnimationEventHandler<HTMLElement> | undefined;
2646
- onAnimationEndCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
2647
- onAnimationIteration?: react.AnimationEventHandler<HTMLElement> | undefined;
2648
- onAnimationIterationCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
2649
- onToggle?: react.ToggleEventHandler<HTMLElement> | undefined;
2650
- onBeforeToggle?: react.ToggleEventHandler<HTMLElement> | undefined;
2651
- onTransitionCancel?: react.TransitionEventHandler<HTMLElement> | undefined;
2652
- onTransitionCancelCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2653
- onTransitionEnd?: react.TransitionEventHandler<HTMLElement> | undefined;
2654
- onTransitionEndCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2655
- onTransitionRun?: react.TransitionEventHandler<HTMLElement> | undefined;
2656
- onTransitionRunCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2657
- onTransitionStart?: react.TransitionEventHandler<HTMLElement> | undefined;
2658
- onTransitionStartCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
2659
- };
2660
2093
  };
2661
2094
 
2662
2095
  interface MenuRootProps extends UseMenuProps {
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MenuAnchor, a as MenuContent, b as MenuGroup, c as MenuGroupLabel, d as MenuItem, e as MenuPositioner, f as MenuRoot, g as MenuTrigger } from './Menu-12s-Cfv1stLD.js';
2
- export { u as useMenuContext, h as useMenuItemContext } from './Menu-12s-Cfv1stLD.js';
1
+ import { M as MenuAnchor, a as MenuContent, b as MenuGroup, c as MenuGroupLabel, d as MenuItem, e as MenuPositioner, f as MenuRoot, g as MenuTrigger } from './Menu-12s-BZlYyVsk.js';
2
+ export { u as useMenuContext, h as useMenuItemContext } from './Menu-12s-BZlYyVsk.js';
3
3
 
4
4
  var Menu_namespace = {
5
5
  __proto__: null,
@@ -43,9 +43,6 @@ function useMenuState(props) {
43
43
  const elementsRef = React.useRef([]);
44
44
  const labelsRef = React.useRef([]);
45
45
  const triggerRef = React.useRef(null);
46
- const groupIndexCounter = React.useRef(0);
47
- groupIndexCounter.current = 0;
48
- const menuId = React.useId();
49
46
  return {
50
47
  open,
51
48
  setOpenState,
@@ -53,13 +50,11 @@ function useMenuState(props) {
53
50
  setActiveIndex,
54
51
  elementsRef,
55
52
  labelsRef,
56
- triggerRef,
57
- groupIndexCounter,
58
- menuId
53
+ triggerRef
59
54
  };
60
55
  }
61
56
  function useMenu(props) {
62
- const { open, setOpenState, activeIndex, setActiveIndex, elementsRef, labelsRef, triggerRef, groupIndexCounter, menuId } = useMenuState(props);
57
+ const { open, setOpenState, activeIndex, setActiveIndex, elementsRef, labelsRef, triggerRef } = useMenuState(props);
63
58
  const { disabled = false, placement = "bottom", gutter = 8, overflowPadding = 8, strategy = "absolute", matchReferenceWidth = false } = props;
64
59
  const [safeArea, setSafeArea] = React.useState({
65
60
  top: 0,
@@ -276,49 +271,38 @@ function useMenu(props) {
276
271
  "aria-disabled": itemProps.disabled ? "true" : undefined
277
272
  })
278
273
  };
279
- },
280
- // implement when submenu is needed
281
- // getSubmenuTriggerProps: (itemProps: UseMenuSubmenuTriggerProps, index: number) => {
282
- // const isActive = activeIndex === index;
283
- //
284
- // const itemStateProps = elementProps({
285
- // "data-highlighted": dataAttr(isActive),
286
- // "data-disabled": dataAttr(itemProps.disabled),
287
- // });
288
- //
289
- // return {
290
- // isHighlighted: isActive,
291
- // isDisabled: itemProps.disabled,
292
- //
293
- // stateProps: itemStateProps,
294
- //
295
- // rootProps: elementProps({
296
- // ...itemStateProps,
297
- // ...triggerInteractions.getItemProps(),
298
- // role: "menuitem",
299
- // tabIndex: isActive ? 0 : -1,
300
- // "aria-disabled": itemProps.disabled ? "true" : undefined,
301
- // }),
302
- // };
303
- // },
304
- getGroupProps: ()=>{
305
- const groupIndex = groupIndexCounter.current++;
306
- const labelId = `menu:${menuId}:group-${groupIndex}:label`;
307
- return {
308
- labelId,
309
- rootProps: domUtils.elementProps({
310
- role: "group",
311
- "aria-labelledby": labelId
312
- })
313
- };
314
- },
315
- getGroupLabelProps: (labelId)=>{
316
- return domUtils.elementProps({
317
- role: "presentation",
318
- id: labelId
319
- });
320
274
  }
321
275
  };
322
276
  }
277
+ // A group advertises aria-labelledby only while its label is actually rendered.
278
+ // Mirrors useFieldset: a callback ref flips a boolean synchronously at commit, so
279
+ // the attribute is present on first paint and never points at a missing id — no
280
+ // menu-global registry or render-order ids needed. Each group owns its own id and
281
+ // presence flag, so conditionally rendering or reordering groups can never make one
282
+ // group inherit another's label reference.
283
+ function useMenuGroup() {
284
+ const id = React.useId();
285
+ const labelId = `menu-group:${id}:label`;
286
+ const [isLabelRendered, setIsLabelRendered] = React.useState(false);
287
+ const labelRef = React.useCallback((node)=>{
288
+ setIsLabelRendered(!!node);
289
+ }, []);
290
+ return {
291
+ refs: {
292
+ label: labelRef
293
+ },
294
+ rootProps: domUtils.elementProps({
295
+ role: "group",
296
+ ...isLabelRendered && {
297
+ "aria-labelledby": labelId
298
+ }
299
+ }),
300
+ labelProps: domUtils.elementProps({
301
+ role: "presentation",
302
+ id: labelId
303
+ })
304
+ };
305
+ }
323
306
 
324
307
  exports.useMenu = useMenu;
308
+ exports.useMenuGroup = useMenuGroup;
@@ -2,7 +2,7 @@
2
2
  import { useFloating, offset, size, flip, shift, useTransitionStatus, autoUpdate, useClick, useRole, useListNavigation, useTypeahead, useInteractions } from '@floating-ui/react';
3
3
  import { useControllableState } from '@seed-design/react-use-controllable-state';
4
4
  import { elementProps, dataAttr, buttonProps } from '@seed-design/dom-utils';
5
- import { useState, useCallback, useEffect, useMemo, useRef, useId } from 'react';
5
+ import { useId, useState, useCallback, useEffect, useMemo, useRef } from 'react';
6
6
 
7
7
  const MIN_HEIGHT = 200;
8
8
  // flip/size/shift derive collisions from numeric padding, so the safe-area insets
@@ -43,9 +43,6 @@ function useMenuState(props) {
43
43
  const elementsRef = useRef([]);
44
44
  const labelsRef = useRef([]);
45
45
  const triggerRef = useRef(null);
46
- const groupIndexCounter = useRef(0);
47
- groupIndexCounter.current = 0;
48
- const menuId = useId();
49
46
  return {
50
47
  open,
51
48
  setOpenState,
@@ -53,13 +50,11 @@ function useMenuState(props) {
53
50
  setActiveIndex,
54
51
  elementsRef,
55
52
  labelsRef,
56
- triggerRef,
57
- groupIndexCounter,
58
- menuId
53
+ triggerRef
59
54
  };
60
55
  }
61
56
  function useMenu(props) {
62
- const { open, setOpenState, activeIndex, setActiveIndex, elementsRef, labelsRef, triggerRef, groupIndexCounter, menuId } = useMenuState(props);
57
+ const { open, setOpenState, activeIndex, setActiveIndex, elementsRef, labelsRef, triggerRef } = useMenuState(props);
63
58
  const { disabled = false, placement = "bottom", gutter = 8, overflowPadding = 8, strategy = "absolute", matchReferenceWidth = false } = props;
64
59
  const [safeArea, setSafeArea] = useState({
65
60
  top: 0,
@@ -276,49 +271,37 @@ function useMenu(props) {
276
271
  "aria-disabled": itemProps.disabled ? "true" : undefined
277
272
  })
278
273
  };
279
- },
280
- // implement when submenu is needed
281
- // getSubmenuTriggerProps: (itemProps: UseMenuSubmenuTriggerProps, index: number) => {
282
- // const isActive = activeIndex === index;
283
- //
284
- // const itemStateProps = elementProps({
285
- // "data-highlighted": dataAttr(isActive),
286
- // "data-disabled": dataAttr(itemProps.disabled),
287
- // });
288
- //
289
- // return {
290
- // isHighlighted: isActive,
291
- // isDisabled: itemProps.disabled,
292
- //
293
- // stateProps: itemStateProps,
294
- //
295
- // rootProps: elementProps({
296
- // ...itemStateProps,
297
- // ...triggerInteractions.getItemProps(),
298
- // role: "menuitem",
299
- // tabIndex: isActive ? 0 : -1,
300
- // "aria-disabled": itemProps.disabled ? "true" : undefined,
301
- // }),
302
- // };
303
- // },
304
- getGroupProps: ()=>{
305
- const groupIndex = groupIndexCounter.current++;
306
- const labelId = `menu:${menuId}:group-${groupIndex}:label`;
307
- return {
308
- labelId,
309
- rootProps: elementProps({
310
- role: "group",
311
- "aria-labelledby": labelId
312
- })
313
- };
314
- },
315
- getGroupLabelProps: (labelId)=>{
316
- return elementProps({
317
- role: "presentation",
318
- id: labelId
319
- });
320
274
  }
321
275
  };
322
276
  }
277
+ // A group advertises aria-labelledby only while its label is actually rendered.
278
+ // Mirrors useFieldset: a callback ref flips a boolean synchronously at commit, so
279
+ // the attribute is present on first paint and never points at a missing id — no
280
+ // menu-global registry or render-order ids needed. Each group owns its own id and
281
+ // presence flag, so conditionally rendering or reordering groups can never make one
282
+ // group inherit another's label reference.
283
+ function useMenuGroup() {
284
+ const id = useId();
285
+ const labelId = `menu-group:${id}:label`;
286
+ const [isLabelRendered, setIsLabelRendered] = useState(false);
287
+ const labelRef = useCallback((node)=>{
288
+ setIsLabelRendered(!!node);
289
+ }, []);
290
+ return {
291
+ refs: {
292
+ label: labelRef
293
+ },
294
+ rootProps: elementProps({
295
+ role: "group",
296
+ ...isLabelRendered && {
297
+ "aria-labelledby": labelId
298
+ }
299
+ }),
300
+ labelProps: elementProps({
301
+ role: "presentation",
302
+ id: labelId
303
+ })
304
+ };
305
+ }
323
306
 
324
- export { useMenu as u };
307
+ export { useMenu as a, useMenuGroup as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-design/react-menu",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/daangn/seed-design.git",
@@ -24,8 +24,7 @@
24
24
  "scripts": {
25
25
  "clean": "rm -rf lib",
26
26
  "build": "bunchee",
27
- "lint:publish": "bun publint",
28
- "test": "vitest run"
27
+ "lint:publish": "bun publint"
29
28
  },
30
29
  "dependencies": {
31
30
  "@floating-ui/react": "^0.27.0",
@@ -38,10 +37,8 @@
38
37
  },
39
38
  "devDependencies": {
40
39
  "@types/react": "^19.1.6",
41
- "jsdom": "^29.0.2",
42
40
  "react": "^19.1.0",
43
- "react-dom": "^19.1.0",
44
- "vitest": "^4.1.3"
41
+ "react-dom": "^19.1.0"
45
42
  },
46
43
  "peerDependencies": {
47
44
  "react": ">=18.0.0",
package/src/Menu.tsx CHANGED
@@ -12,11 +12,17 @@ import { DismissibleLayer } from "@seed-design/react-dismissible-layer";
12
12
  import { mergeProps } from "@seed-design/dom-utils";
13
13
  import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
14
14
  import React, { forwardRef, createContext } from "react";
15
- import { useMenu, type UseMenuItemProps, type UseMenuProps } from "./useMenu";
15
+ import {
16
+ useMenu,
17
+ useMenuGroup,
18
+ type UseMenuGroupReturn,
19
+ type UseMenuItemProps,
20
+ type UseMenuProps,
21
+ } from "./useMenu";
16
22
  import { MenuProvider, useMenuContext } from "./useMenuContext";
17
23
  import { MenuItemProvider } from "./useMenuItemContext";
18
24
 
19
- const MenuGroupLabelIdContext = createContext<string | null>(null);
25
+ const MenuGroupContext = createContext<UseMenuGroupReturn | null>(null);
20
26
 
21
27
  export interface MenuRootProps extends UseMenuProps {
22
28
  children?: React.ReactNode;
@@ -198,13 +204,12 @@ MenuItem.displayName = "MenuItem";
198
204
  export interface MenuGroupProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
199
205
 
200
206
  export const MenuGroup = forwardRef<HTMLDivElement, MenuGroupProps>((props, ref) => {
201
- const { getGroupProps } = useMenuContext();
202
- const { labelId, rootProps } = getGroupProps();
207
+ const group = useMenuGroup();
203
208
 
204
209
  return (
205
- <MenuGroupLabelIdContext.Provider value={labelId}>
206
- <Primitive.div ref={ref} {...mergeProps(rootProps, props)} />
207
- </MenuGroupLabelIdContext.Provider>
210
+ <MenuGroupContext.Provider value={group}>
211
+ <Primitive.div ref={ref} {...mergeProps(group.rootProps, props)} />
212
+ </MenuGroupContext.Provider>
208
213
  );
209
214
  });
210
215
  MenuGroup.displayName = "MenuGroup";
@@ -212,10 +217,16 @@ MenuGroup.displayName = "MenuGroup";
212
217
  export interface MenuGroupLabelProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
213
218
 
214
219
  export const MenuGroupLabel = forwardRef<HTMLDivElement, MenuGroupLabelProps>((props, ref) => {
215
- const { getGroupLabelProps } = useMenuContext();
216
- const labelId = React.useContext(MenuGroupLabelIdContext);
217
- if (!labelId) throw new Error("MenuGroupLabel must be used within a MenuGroup");
220
+ const group = React.useContext(MenuGroupContext);
221
+ if (!group) throw new Error("MenuGroupLabel must be used within a MenuGroup");
218
222
 
219
- return <Primitive.div ref={ref} {...mergeProps(getGroupLabelProps(labelId), props)} />;
223
+ // Compose the group's label ref so the group advertises aria-labelledby only
224
+ // while this label is actually rendered (see useMenuGroup).
225
+ return (
226
+ <Primitive.div
227
+ ref={composeRefs(group.refs.label, ref)}
228
+ {...mergeProps(group.labelProps, props)}
229
+ />
230
+ );
220
231
  });
221
232
  MenuGroupLabel.displayName = "MenuGroupLabel";
@@ -1,17 +1,6 @@
1
- // this file is .vitest.tsx, not .test.tsx — so bun test won't pick it up.
2
- //
3
- // @floating-ui/react defers focus via requestAnimationFrame (enqueueFocus).
4
- // bun test preloads happydom, which doesn't fire rAF the way we need.
5
- // vitest + jsdom (pretendToBeVisual) gives us a real rAF that ticks at ~16ms,
6
- // letting waitForFocus() actually flush the deferred .focus() calls.
7
- //
8
- // see vitest.config.ts for the jsdom environment setup.
9
-
10
- /// <reference types="@testing-library/jest-dom/vitest" />
11
-
12
1
  import { render, fireEvent, act } from "@testing-library/react";
13
2
  import userEvent from "@testing-library/user-event";
14
- import { describe, expect, it, vi } from "vitest";
3
+ import { describe, expect, it, jest } from "bun:test";
15
4
 
16
5
  import * as React from "react";
17
6
 
@@ -33,8 +22,8 @@ type UseMenuProps = MenuRootProps;
33
22
  const waitForPositioning = () => act(async () => {});
34
23
 
35
24
  // Flush rAF-deferred focus from FloatingFocusManager / useListNavigation.
36
- // jsdom (pretendToBeVisual) fires rAF callbacks every ~16 ms via setInterval,
37
- // so a short timer is needed for enqueueFocus() in @floating-ui/react to land.
25
+ // happy-dom mocks rAF with setImmediate, so a short timer is needed for
26
+ // enqueueFocus() in @floating-ui/react to land.
38
27
  const waitForFocus = () =>
39
28
  act(async () => {
40
29
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -198,6 +187,31 @@ describe("useMenu", () => {
198
187
  const label = getByText("Group 1");
199
188
  expect(label).toHaveAttribute("id", labelledBy);
200
189
  });
190
+
191
+ it("does not set a dangling aria-labelledby on a group without a label", async () => {
192
+ function MenuWithUnlabeledGroup() {
193
+ return (
194
+ <Menu>
195
+ <MenuTrigger>Open Menu</MenuTrigger>
196
+ <MenuPositioner>
197
+ <MenuContent>
198
+ <MenuGroup>
199
+ <MenuItem>Item A</MenuItem>
200
+ <MenuItem>Item B</MenuItem>
201
+ </MenuGroup>
202
+ </MenuContent>
203
+ </MenuPositioner>
204
+ </Menu>
205
+ );
206
+ }
207
+
208
+ const user = userEvent.setup();
209
+ const { getAllByRole, getByText } = render(<MenuWithUnlabeledGroup />);
210
+ await waitForPositioning();
211
+ await user.click(getByText("Open Menu"));
212
+ const group = getAllByRole("group")[0];
213
+ expect(group).not.toHaveAttribute("aria-labelledby");
214
+ });
201
215
  });
202
216
 
203
217
  describe("open/close state", () => {
@@ -222,7 +236,7 @@ describe("useMenu", () => {
222
236
 
223
237
  it("supports controlled open state", async () => {
224
238
  const user = userEvent.setup();
225
- const onOpenChange = vi.fn();
239
+ const onOpenChange = jest.fn();
226
240
  const { getByText } = render(<ControlledMenu onOpenChange={onOpenChange} />);
227
241
  await waitForPositioning();
228
242
  await user.click(getByText("Open Menu"));
@@ -237,7 +251,7 @@ describe("useMenu", () => {
237
251
 
238
252
  it("calls onOpenChange when toggled", async () => {
239
253
  const user = userEvent.setup();
240
- const onOpenChange = vi.fn();
254
+ const onOpenChange = jest.fn();
241
255
  const { getByText } = render(<BasicMenu onOpenChange={onOpenChange} />);
242
256
  await waitForPositioning();
243
257
  await user.click(getByText("Open Menu"));
@@ -249,7 +263,7 @@ describe("useMenu", () => {
249
263
 
250
264
  it("reports reason 'escapeKeyDown' when closed by Escape", async () => {
251
265
  const user = userEvent.setup();
252
- const onOpenChange = vi.fn();
266
+ const onOpenChange = jest.fn();
253
267
  const { getByText } = render(<BasicMenu onOpenChange={onOpenChange} />);
254
268
  await waitForPositioning();
255
269
  await user.click(getByText("Open Menu"));
@@ -263,7 +277,7 @@ describe("useMenu", () => {
263
277
 
264
278
  it("reports reason 'interactOutside' when closed by outside click", async () => {
265
279
  const user = userEvent.setup();
266
- const onOpenChange = vi.fn();
280
+ const onOpenChange = jest.fn();
267
281
  const { getByText } = render(
268
282
  <div>
269
283
  <BasicMenu onOpenChange={onOpenChange} />
@@ -282,7 +296,7 @@ describe("useMenu", () => {
282
296
 
283
297
  it("reports reason 'itemClick' when closed by item selection", async () => {
284
298
  const user = userEvent.setup();
285
- const onOpenChange = vi.fn();
299
+ const onOpenChange = jest.fn();
286
300
  const { getByText } = render(<BasicMenu onOpenChange={onOpenChange} />);
287
301
  await waitForPositioning();
288
302
  await user.click(getByText("Open Menu"));
@@ -529,7 +543,7 @@ describe("useMenu", () => {
529
543
  describe("item interaction", () => {
530
544
  it("calls onClick on item when clicked", async () => {
531
545
  const user = userEvent.setup();
532
- const onClick = vi.fn();
546
+ const onClick = jest.fn();
533
547
  const { getByText } = render(
534
548
  <Menu>
535
549
  <MenuTrigger>Open Menu</MenuTrigger>
@@ -566,7 +580,7 @@ describe("useMenu", () => {
566
580
 
567
581
  it("activates focused item on Enter key", async () => {
568
582
  const user = userEvent.setup();
569
- const onClick = vi.fn();
583
+ const onClick = jest.fn();
570
584
  const { getByText } = render(
571
585
  <Menu>
572
586
  <MenuTrigger>Open Menu</MenuTrigger>
@@ -579,14 +593,14 @@ describe("useMenu", () => {
579
593
  );
580
594
  await waitForPositioning();
581
595
  await user.click(getByText("Open Menu"));
582
- getByText("Activatable").focus();
596
+ act(() => getByText("Activatable").focus());
583
597
  await user.keyboard("{Enter}");
584
598
  expect(onClick).toHaveBeenCalledTimes(1);
585
599
  });
586
600
 
587
601
  it("activates focused item on Space key", async () => {
588
602
  const user = userEvent.setup();
589
- const onClick = vi.fn();
603
+ const onClick = jest.fn();
590
604
  const { getByText } = render(
591
605
  <Menu>
592
606
  <MenuTrigger>Open Menu</MenuTrigger>
@@ -599,14 +613,14 @@ describe("useMenu", () => {
599
613
  );
600
614
  await waitForPositioning();
601
615
  await user.click(getByText("Open Menu"));
602
- getByText("Activatable").focus();
616
+ act(() => getByText("Activatable").focus());
603
617
  await user.keyboard(" ");
604
618
  expect(onClick).toHaveBeenCalledTimes(1);
605
619
  });
606
620
 
607
621
  it("does not activate disabled item on click or keyboard", async () => {
608
622
  const user = userEvent.setup();
609
- const onClick = vi.fn();
623
+ const onClick = jest.fn();
610
624
  const { getByText } = render(
611
625
  <Menu>
612
626
  <MenuTrigger>Open Menu</MenuTrigger>
@@ -736,7 +750,7 @@ describe("useMenu", () => {
736
750
 
737
751
  it("does not cascade-dismiss Menu B when Menu A's layer is removed", async () => {
738
752
  const user = userEvent.setup();
739
- const onMenuBOpenChange = vi.fn();
753
+ const onMenuBOpenChange = jest.fn();
740
754
  const { getByText } = render(<TwoSiblingMenus onMenuBOpenChange={onMenuBOpenChange} />);
741
755
  await waitForPositioning();
742
756
 
@@ -785,7 +799,7 @@ describe("useMenu", () => {
785
799
 
786
800
  it("does not cascade-dismiss Menu B on touch switch (touch)", async () => {
787
801
  const user = userEvent.setup();
788
- const onMenuBOpenChange = vi.fn();
802
+ const onMenuBOpenChange = jest.fn();
789
803
  const { getByText } = render(<TwoSiblingMenus onMenuBOpenChange={onMenuBOpenChange} />);
790
804
  await waitForPositioning();
791
805
 
@@ -813,7 +827,7 @@ describe("useMenu", () => {
813
827
 
814
828
  it("keeps Menu B open and interactive after switching from Menu A", async () => {
815
829
  const user = userEvent.setup();
816
- const onClick = vi.fn();
830
+ const onClick = jest.fn();
817
831
  const { getByText } = render(
818
832
  <div>
819
833
  <Menu>
@@ -848,7 +862,7 @@ describe("useMenu", () => {
848
862
 
849
863
  describe("mouse interaction", () => {
850
864
  it("activates item on mouse-up after drag from trigger", async () => {
851
- const onClick = vi.fn();
865
+ const onClick = jest.fn();
852
866
  const { getByText } = render(
853
867
  <Menu>
854
868
  <MenuTrigger>Open Menu</MenuTrigger>
package/src/useMenu.ts CHANGED
@@ -142,11 +142,6 @@ function useMenuState(props: UseMenuStateProps) {
142
142
  const labelsRef = useRef<(string | null)[]>([]);
143
143
  const triggerRef = useRef<Element | null>(null);
144
144
 
145
- const groupIndexCounter = useRef(0);
146
- groupIndexCounter.current = 0;
147
-
148
- const menuId = useId();
149
-
150
145
  return {
151
146
  open,
152
147
  setOpenState,
@@ -155,23 +150,12 @@ function useMenuState(props: UseMenuStateProps) {
155
150
  elementsRef,
156
151
  labelsRef,
157
152
  triggerRef,
158
- groupIndexCounter,
159
- menuId,
160
153
  };
161
154
  }
162
155
 
163
156
  export function useMenu(props: UseMenuProps) {
164
- const {
165
- open,
166
- setOpenState,
167
- activeIndex,
168
- setActiveIndex,
169
- elementsRef,
170
- labelsRef,
171
- triggerRef,
172
- groupIndexCounter,
173
- menuId,
174
- } = useMenuState(props);
157
+ const { open, setOpenState, activeIndex, setActiveIndex, elementsRef, labelsRef, triggerRef } =
158
+ useMenuState(props);
175
159
 
176
160
  const {
177
161
  disabled = false,
@@ -443,24 +427,39 @@ export function useMenu(props: UseMenuProps) {
443
427
  // }),
444
428
  // };
445
429
  // },
430
+ };
431
+ }
446
432
 
447
- getGroupProps: () => {
448
- const groupIndex = groupIndexCounter.current++;
449
- const labelId = `menu:${menuId}:group-${groupIndex}:label`;
450
- return {
451
- labelId,
452
- rootProps: elementProps({
453
- role: "group",
454
- "aria-labelledby": labelId,
455
- }),
456
- };
457
- },
433
+ export type UseMenuGroupReturn = ReturnType<typeof useMenuGroup>;
458
434
 
459
- getGroupLabelProps: (labelId: string) => {
460
- return elementProps({
461
- role: "presentation",
462
- id: labelId,
463
- });
435
+ // A group advertises aria-labelledby only while its label is actually rendered.
436
+ // Mirrors useFieldset: a callback ref flips a boolean synchronously at commit, so
437
+ // the attribute is present on first paint and never points at a missing id — no
438
+ // menu-global registry or render-order ids needed. Each group owns its own id and
439
+ // presence flag, so conditionally rendering or reordering groups can never make one
440
+ // group inherit another's label reference.
441
+ export function useMenuGroup() {
442
+ const id = useId();
443
+ const labelId = `menu-group:${id}:label`;
444
+
445
+ const [isLabelRendered, setIsLabelRendered] = useState(false);
446
+ const labelRef = useCallback((node: HTMLDivElement | null) => {
447
+ setIsLabelRendered(!!node);
448
+ }, []);
449
+
450
+ return {
451
+ refs: {
452
+ label: labelRef,
464
453
  },
454
+
455
+ rootProps: elementProps({
456
+ role: "group",
457
+ ...(isLabelRendered && { "aria-labelledby": labelId }),
458
+ }),
459
+
460
+ labelProps: elementProps({
461
+ role: "presentation",
462
+ id: labelId,
463
+ }),
465
464
  };
466
465
  }