@mortenbrudvik/waveui 0.11.0 → 0.12.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.
Files changed (116) hide show
  1. package/README.md +97 -2
  2. package/dist/components/button/Link.cjs +1 -1
  3. package/dist/components/button/Link.cjs.map +1 -1
  4. package/dist/components/button/Link.mjs +4 -4
  5. package/dist/components/data-display/AvatarGroup.cjs +1 -1
  6. package/dist/components/data-display/AvatarGroup.cjs.map +1 -1
  7. package/dist/components/data-display/AvatarGroup.mjs +10 -10
  8. package/dist/components/data-display/InfoButton.cjs +1 -1
  9. package/dist/components/data-display/InfoButton.cjs.map +1 -1
  10. package/dist/components/data-display/InfoButton.mjs +12 -12
  11. package/dist/components/feedback/Toaster.cjs +1 -1
  12. package/dist/components/feedback/Toaster.cjs.map +1 -1
  13. package/dist/components/feedback/Toaster.mjs +235 -235
  14. package/dist/components/feedback/Toaster.mjs.map +1 -1
  15. package/dist/components/input/Combobox.cjs +1 -1
  16. package/dist/components/input/Combobox.cjs.map +1 -1
  17. package/dist/components/input/Combobox.mjs +176 -175
  18. package/dist/components/input/Combobox.mjs.map +1 -1
  19. package/dist/components/input/DatePicker.cjs +1 -1
  20. package/dist/components/input/DatePicker.cjs.map +1 -1
  21. package/dist/components/input/DatePicker.mjs +188 -187
  22. package/dist/components/input/DatePicker.mjs.map +1 -1
  23. package/dist/components/input/Dropdown.cjs +1 -1
  24. package/dist/components/input/Dropdown.cjs.map +1 -1
  25. package/dist/components/input/Dropdown.mjs +41 -40
  26. package/dist/components/input/Dropdown.mjs.map +1 -1
  27. package/dist/components/input/Option.cjs +1 -1
  28. package/dist/components/input/Option.cjs.map +1 -1
  29. package/dist/components/input/Option.mjs +89 -87
  30. package/dist/components/input/Option.mjs.map +1 -1
  31. package/dist/components/input/TagPicker.root.cjs +1 -1
  32. package/dist/components/input/TagPicker.root.cjs.map +1 -1
  33. package/dist/components/input/TagPicker.root.mjs +136 -135
  34. package/dist/components/input/TagPicker.root.mjs.map +1 -1
  35. package/dist/components/input/TimePicker.cjs +1 -1
  36. package/dist/components/input/TimePicker.cjs.map +1 -1
  37. package/dist/components/input/TimePicker.mjs +156 -154
  38. package/dist/components/input/TimePicker.mjs.map +1 -1
  39. package/dist/components/navigation/Menu.popover.cjs +1 -1
  40. package/dist/components/navigation/Menu.popover.cjs.map +1 -1
  41. package/dist/components/navigation/Menu.popover.mjs +137 -127
  42. package/dist/components/navigation/Menu.popover.mjs.map +1 -1
  43. package/dist/components/navigation/Menu.root.cjs +1 -1
  44. package/dist/components/navigation/Menu.root.cjs.map +1 -1
  45. package/dist/components/navigation/Menu.root.mjs +4 -4
  46. package/dist/components/overlays/Dialog.cjs +1 -1
  47. package/dist/components/overlays/Dialog.cjs.map +1 -1
  48. package/dist/components/overlays/Dialog.mjs +123 -123
  49. package/dist/components/overlays/Dialog.mjs.map +1 -1
  50. package/dist/components/overlays/Drawer.panel.cjs +1 -1
  51. package/dist/components/overlays/Drawer.panel.cjs.map +1 -1
  52. package/dist/components/overlays/Drawer.panel.mjs +12 -12
  53. package/dist/components/overlays/Drawer.panel.mjs.map +1 -1
  54. package/dist/components/overlays/Popover.cjs +1 -1
  55. package/dist/components/overlays/Popover.cjs.map +1 -1
  56. package/dist/components/overlays/Popover.mjs +173 -162
  57. package/dist/components/overlays/Popover.mjs.map +1 -1
  58. package/dist/components/overlays/TeachingPopover.cjs +1 -1
  59. package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
  60. package/dist/components/overlays/TeachingPopover.mjs +96 -91
  61. package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
  62. package/dist/components/overlays/Tooltip.cjs +1 -1
  63. package/dist/components/overlays/Tooltip.cjs.map +1 -1
  64. package/dist/components/overlays/Tooltip.mjs +47 -47
  65. package/dist/components/overlays/Tooltip.mjs.map +1 -1
  66. package/dist/components/portal/Portal.cjs +1 -1
  67. package/dist/components/portal/Portal.cjs.map +1 -1
  68. package/dist/components/portal/Portal.mjs +5 -5
  69. package/dist/components/table/DataGrid.cjs +1 -1
  70. package/dist/components/table/DataGrid.cjs.map +1 -1
  71. package/dist/components/table/DataGrid.mjs +1 -1
  72. package/dist/hooks/useDismiss.cjs.map +1 -1
  73. package/dist/hooks/useDismiss.mjs.map +1 -1
  74. package/dist/hooks/useFocusTrap.cjs.map +1 -1
  75. package/dist/hooks/useFocusTrap.mjs.map +1 -1
  76. package/dist/hooks/useFocusVisible.cjs +2 -0
  77. package/dist/hooks/useFocusVisible.cjs.map +1 -0
  78. package/dist/hooks/useFocusVisible.mjs +49 -0
  79. package/dist/hooks/useFocusVisible.mjs.map +1 -0
  80. package/dist/hooks/useFocusableGroup.cjs +2 -0
  81. package/dist/hooks/useFocusableGroup.cjs.map +1 -0
  82. package/dist/hooks/useFocusableGroup.mjs +70 -0
  83. package/dist/hooks/useFocusableGroup.mjs.map +1 -0
  84. package/dist/hooks/useModalLayer.cjs +1 -1
  85. package/dist/hooks/useModalLayer.cjs.map +1 -1
  86. package/dist/hooks/useModalLayer.mjs +4 -4
  87. package/dist/hooks/useModalOpen.cjs +2 -0
  88. package/dist/hooks/useModalOpen.cjs.map +1 -0
  89. package/dist/hooks/useModalOpen.mjs +14 -0
  90. package/dist/hooks/useModalOpen.mjs.map +1 -0
  91. package/dist/hooks/usePopupPosition.cjs +1 -1
  92. package/dist/hooks/usePopupPosition.cjs.map +1 -1
  93. package/dist/hooks/usePopupPosition.mjs +82 -53
  94. package/dist/hooks/usePopupPosition.mjs.map +1 -1
  95. package/dist/hooks/useResolvedTarget.cjs +2 -0
  96. package/dist/hooks/useResolvedTarget.cjs.map +1 -0
  97. package/dist/hooks/useResolvedTarget.mjs +37 -0
  98. package/dist/hooks/useResolvedTarget.mjs.map +1 -0
  99. package/dist/hooks/useRovingGrid.cjs +1 -1
  100. package/dist/hooks/useRovingGrid.cjs.map +1 -1
  101. package/dist/hooks/useRovingGrid.mjs +8 -57
  102. package/dist/hooks/useRovingGrid.mjs.map +1 -1
  103. package/dist/hooks/useRovingTabIndex.cjs +1 -1
  104. package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
  105. package/dist/hooks/useRovingTabIndex.mjs +142 -107
  106. package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
  107. package/dist/index.cjs +1 -1
  108. package/dist/index.d.cts +814 -18
  109. package/dist/index.d.ts +814 -18
  110. package/dist/index.mjs +120 -108
  111. package/dist/lib/layers.cjs +1 -1
  112. package/dist/lib/layers.cjs.map +1 -1
  113. package/dist/lib/layers.mjs +112 -109
  114. package/dist/lib/layers.mjs.map +1 -1
  115. package/dist/styles.css +1 -1
  116. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -2345,6 +2345,13 @@ export declare interface ComboboxProps<M extends boolean = false> extends Omit<R
2345
2345
  * listbox keeps its size.
2346
2346
  */
2347
2347
  size?: CoreSize;
2348
+ /**
2349
+ * Advanced positioning of the popup (Fluent's `positioning`): `offset`, `fitViewport`,
2350
+ * `matchReferenceWidth` and `fallbackPlacements` (tried in order when the requested side has no
2351
+ * room). The popup opens below the field.
2352
+ * @default `{ matchReferenceWidth: true, fitViewport: true }`
2353
+ */
2354
+ positioning?: PopupPositioningOptions;
2348
2355
  /**
2349
2356
  * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),
2350
2357
  * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible
@@ -3239,6 +3246,13 @@ export declare interface DatePickerProps extends Omit<React_2.HTMLAttributes<HTM
3239
3246
  * calendar keeps its size.
3240
3247
  */
3241
3248
  size?: CoreSize;
3249
+ /**
3250
+ * Advanced positioning of the popup (Fluent's `positioning`): `offset`, `fitViewport`,
3251
+ * `matchReferenceWidth` and `fallbackPlacements` (tried in order when the requested side has no
3252
+ * room). The popup opens below the field.
3253
+ * @default `{}`: the calendar opens 4px below the field
3254
+ */
3255
+ positioning?: PopupPositioningOptions;
3242
3256
  /**
3243
3257
  * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),
3244
3258
  * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible
@@ -3799,6 +3813,23 @@ export declare interface DialogTriggerRenderProps extends React_2.HTMLAttributes
3799
3813
  ref: React_2.RefCallback<HTMLElement>;
3800
3814
  }
3801
3815
 
3816
+ /** Returned by {@link useDismiss}. */
3817
+ export declare interface DismissLayer {
3818
+ /** The layer's id: pass it to `Portal layerId` or `DismissLayerProvider` around the surface. */
3819
+ layerId: string;
3820
+ /** Whether the layer is currently the topmost open layer (read at call time). */
3821
+ isTopmost(): boolean;
3822
+ }
3823
+
3824
+ /**
3825
+ * Makes `layerId` the parent layer of everything rendered inside (`Portal layerId` does this for
3826
+ * its children automatically).
3827
+ */
3828
+ export declare function DismissLayerProvider(props: {
3829
+ layerId: string;
3830
+ children: React_2.ReactNode;
3831
+ }): React_2.ReactElement;
3832
+
3802
3833
  /** Why a popup layer is dismissed: Escape, a press outside it, or focus moving outside it. */
3803
3834
  export declare type DismissReason = 'escape' | 'outside-press' | 'focus-outside';
3804
3835
 
@@ -4697,6 +4728,13 @@ export declare interface DropdownProps<M extends boolean = false> extends Omit<R
4697
4728
  * listbox keeps its size; the multi-select value text and clear button follow it.
4698
4729
  */
4699
4730
  size?: CoreSize;
4731
+ /**
4732
+ * Advanced positioning of the popup (Fluent's `positioning`): `offset`, `fitViewport`,
4733
+ * `matchReferenceWidth` and `fallbackPlacements` (tried in order when the requested side has no
4734
+ * room). The popup opens below the field.
4735
+ * @default `{ matchReferenceWidth: true, fitViewport: true }`
4736
+ */
4737
+ positioning?: PopupPositioningOptions;
4700
4738
  /**
4701
4739
  * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),
4702
4740
  * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible
@@ -5190,12 +5228,54 @@ export declare interface FlexOwnProps {
5190
5228
  */
5191
5229
  export declare type FlexProps<C extends React_2.ElementType = 'div'> = PolymorphicProps<C, FlexOwnProps>;
5192
5230
 
5231
+ /** Props to spread onto the group element (compose its handlers with your own). */
5232
+ export declare interface FocusableGroupProps {
5233
+ /** The group is itself focusable. */
5234
+ tabIndex: 0;
5235
+ onKeyDown: React_2.KeyboardEventHandler<HTMLElement>;
5236
+ onFocusCapture: React_2.FocusEventHandler<HTMLElement>;
5237
+ /** Marks the element as a group: nested groups own their own contents. */
5238
+ 'data-focusable-group': '';
5239
+ }
5240
+
5241
+ /** How Tab and Enter treat the elements inside a focusable group. */
5242
+ export declare type FocusableGroupTabBehavior = 'unlimited' | 'limited' | 'limited-trap-focus';
5243
+
5193
5244
  /**
5194
5245
  * How the keyboard reaches the items of a set: `'tab'`, every item is a Tab stop and the arrow
5195
5246
  * keys do nothing; `'arrow'`, the set is one Tab stop and the arrow keys move between its items.
5196
5247
  */
5197
5248
  export declare type FocusMode = 'tab' | 'arrow';
5198
5249
 
5250
+ /** Focus-visible ring for focusable controls (C-FOCUS). */
5251
+ export declare const focusRing = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring";
5252
+
5253
+ /** Focus-visible ring drawn inside the element: cells, rows, list and menu items. */
5254
+ export declare const focusRingInset = "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring";
5255
+
5256
+ /** The first tabbable element inside `container`, or `null`. */
5257
+ export declare function getFirstTabbable(container: Element, options?: {
5258
+ includeContainer?: boolean;
5259
+ }): HTMLElement | null;
5260
+
5261
+ /** The last tabbable element inside `container`, or `null`. */
5262
+ export declare function getLastTabbable(container: Element, options?: {
5263
+ includeContainer?: boolean;
5264
+ }): HTMLElement | null;
5265
+
5266
+ /**
5267
+ * The tabbable elements inside `container` in sequential focus order: positive `tabindex` first
5268
+ * (ascending), then `tabindex=0` / natively tabbable elements in document order. Named radio
5269
+ * groups follow {@link isTabbable}, so the result depends on where focus currently is: when focus
5270
+ * is on a radio, the rest of its group is left out, which makes the focused radio the last entry
5271
+ * when its group ends the container (the element a focus trap wraps from).
5272
+ *
5273
+ * @param options.includeContainer Also consider `container` itself.
5274
+ */
5275
+ export declare function getTabbableElements(container: Element, options?: {
5276
+ includeContainer?: boolean;
5277
+ }): HTMLElement[];
5278
+
5199
5279
  /**
5200
5280
  * The classes that select a theme's tokens: `'wave-light'`, `'wave-dark dark'` or
5201
5281
  * `'wave-high-contrast high-contrast'`. Unknown values fall back to the light classes. Safe to call
@@ -5246,6 +5326,13 @@ export declare const gridClassNames: {
5246
5326
  readonly root: "wave-grid";
5247
5327
  };
5248
5328
 
5329
+ /** Handlers {@link useGridNavigation} needs on the grid element (compose them with the consumer's). */
5330
+ export declare interface GridNavigationHandlers {
5331
+ onKeyDown: React_2.KeyboardEventHandler<HTMLTableElement>;
5332
+ onFocus: React_2.FocusEventHandler<HTMLTableElement>;
5333
+ onBlur: React_2.FocusEventHandler<HTMLTableElement>;
5334
+ }
5335
+
5249
5336
  /**
5250
5337
  * The Grid's own props (the XOwnProps rule of `PolymorphicProps`: component-specific props only).
5251
5338
  * Every other prop comes from the rendered element (`as`).
@@ -5339,6 +5426,13 @@ export declare interface HamburgerProps extends React_2.ButtonHTMLAttributes<HTM
5339
5426
  ref?: React_2.Ref<HTMLButtonElement>;
5340
5427
  }
5341
5428
 
5429
+ /**
5430
+ * Whether a modal surface is open now: a layer of kind `'modal'` (a Dialog, an overlay Drawer, an
5431
+ * alert, the DatePicker's calendar, or your own `useDismiss({ kind: 'modal' })`). A non-modal
5432
+ * surface is no modal. Server-safe: `false` when no layer is registered, as on the server.
5433
+ */
5434
+ export declare function hasOpenModal(): boolean;
5435
+
5342
5436
  /** Level of a heading element, `<h1>` … `<h6>`. */
5343
5437
  export declare type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
5344
5438
 
@@ -5732,6 +5826,20 @@ export declare interface InputErrorMessageProps extends React_2.HTMLAttributes<H
5732
5826
  [dataAttribute: `data-${string}`]: unknown;
5733
5827
  }
5734
5828
 
5829
+ /**
5830
+ * Focus indicator of text-entry controls: a 2px primary bottom border. `focus:outline-hidden`
5831
+ * removes the outline while focused but — unlike `outline-none` — keeps a visible outline in
5832
+ * forced-colors mode, where the border colour change is not perceivable. (Scoped to `:focus` so
5833
+ * unfocused inputs do not show that outline in forced colors.)
5834
+ */
5835
+ export declare const inputFocus = "focus:outline-hidden focus:border-b-2 focus:border-b-primary";
5836
+
5837
+ /**
5838
+ * Wrapper form of {@link inputFocus} for inputs rendered inside a styled wrapper (slots,
5839
+ * SearchBox, TagPicker). Put `focus:outline-hidden` on the inner control.
5840
+ */
5841
+ export declare const inputFocusWithin = "focus-within:border-b-2 focus-within:border-b-primary";
5842
+
5735
5843
  /** Properties for the Input component. */
5736
5844
  export declare interface InputProps extends Omit<React_2.InputHTMLAttributes<HTMLInputElement>, 'size'> {
5737
5845
  /**
@@ -6035,6 +6143,16 @@ export declare interface LabelProps extends React_2.LabelHTMLAttributes<HTMLLabe
6035
6143
  ref?: React_2.Ref<HTMLLabelElement>;
6036
6144
  }
6037
6145
 
6146
+ /**
6147
+ * What kind of surface a layer is. `modal` marks dialog-like surfaces (focus-restore validation and
6148
+ * modal isolation look for them); a modal blocks presses and Escape for the layers below it only
6149
+ * while its page isolation is active ({@link registerLayerIsolation}). `dialog` marks a non-modal
6150
+ * Dialog or Drawer: it shields nothing (no isolation), takes Escape only from inside its tree
6151
+ * (`escape: 'inside'`), and the Toaster moves out of its way; focus-restore validation and modal
6152
+ * isolation do not count it.
6153
+ */
6154
+ export declare type LayerKind = 'modal' | 'dialog' | 'popover' | 'menu' | 'listbox' | 'tooltip' | 'toast';
6155
+
6038
6156
  /**
6039
6157
  * A hyperlink with Fluent link styling. Renders an `<a>` by default; `as` renders a router link
6040
6158
  * (`<Link as={RouterLink} to="/">`) or a `<button>` styled as a link (`type="button"` by default).
@@ -6834,7 +6952,7 @@ export declare const Menu: {
6834
6952
  displayName: string;
6835
6953
  };
6836
6954
  Popover: {
6837
- ({ side, align, offset, target, children, className, style, onKeyDown, onKeyDownCapture, onFocus, onPointerEnter, onPointerLeave, onPointerMove, onContextMenu, ref, ...rest }: MenuPopoverProps): JSX.Element | null;
6955
+ ({ side, align, offset, target: targetProp, positioning, children, className, style, onKeyDown, onKeyDownCapture, onFocus, onPointerEnter, onPointerLeave, onPointerMove, onContextMenu, ref, ...rest }: MenuPopoverProps): JSX.Element | null;
6838
6956
  displayName: string;
6839
6957
  };
6840
6958
  ItemCheckbox: {
@@ -7305,7 +7423,7 @@ export declare interface MenuItemSwitchProps extends MenuItemProps, MenuItemSele
7305
7423
  * Also exported as `MenuPopover` (import the flat name from React Server Components).
7306
7424
  */
7307
7425
  export declare const MenuPopover: {
7308
- ({ side, align, offset, target, children, className, style, onKeyDown, onKeyDownCapture, onFocus, onPointerEnter, onPointerLeave, onPointerMove, onContextMenu, ref, ...rest }: MenuPopoverProps): React_2.JSX.Element | null;
7426
+ ({ side, align, offset, target: targetProp, positioning, children, className, style, onKeyDown, onKeyDownCapture, onFocus, onPointerEnter, onPointerLeave, onPointerMove, onContextMenu, ref, ...rest }: MenuPopoverProps): React_2.JSX.Element | null;
7309
7427
  displayName: string;
7310
7428
  };
7311
7429
 
@@ -7331,11 +7449,18 @@ export declare interface MenuPopoverProps extends Omit<React_2.HTMLAttributes<HT
7331
7449
  * with a `target` needs no trigger; name it with `aria-label`, and give a toggle button you use
7332
7450
  * as the target `aria-haspopup="menu"` and `aria-expanded` yourself (the menu's `id` is
7333
7451
  * generated, so the toggle cannot point `aria-controls` at it). A press on a target element
7334
- * does not close the menu. Hold the element in state (a ref cannot be observed;
7335
- * TeachingPopover's `target` also takes a ref). A menu opened by `openOnContext` is placed at
7452
+ * does not close the menu. Hold the element in state, or pass a ref object (read after
7453
+ * each render of the menu). A menu opened by `openOnContext` is placed at
7336
7454
  * the gesture instead.
7337
7455
  */
7338
- target?: PopupTarget;
7456
+ target?: PopupTargetInput;
7457
+ /**
7458
+ * Advanced positioning (Fluent's `positioning`): `offset`, `fitViewport`, `matchReferenceWidth`,
7459
+ * `fallbackPlacements` and `target` (used when the `target` prop is not set). `side` and `align`
7460
+ * stay separate props, and the `offset` prop wins over `positioning.offset`.
7461
+ * @default `{ fitViewport: true }`
7462
+ */
7463
+ positioning?: PopupPositioning;
7339
7464
  /** Menu items and dividers. */
7340
7465
  children: React_2.ReactNode;
7341
7466
  /**
@@ -7798,6 +7923,22 @@ export declare interface MessageBarTitleProps extends React_2.HTMLAttributes<HTM
7798
7923
  ref?: React_2.Ref<HTMLSpanElement>;
7799
7924
  }
7800
7925
 
7926
+ /**
7927
+ * Props that mark an app-owned region (a notification area, a live status bar) so that WaveUI's
7928
+ * modal surfaces leave it usable. Spread them on the region's element: `<div {...modalAllowProps}>`.
7929
+ * Over an open Dialog or Drawer the region
7930
+ *
7931
+ * - counts as inside every dismiss layer, so a press in it closes nothing;
7932
+ * - has its tabbable elements in the Tab cycle of every focus trap;
7933
+ * - is never made `inert` by the modal's page isolation.
7934
+ *
7935
+ * The attribute it sets, `data-wave-focus-trap-allow`, is the one the Toaster's own region
7936
+ * carries, and it is a stable contract.
7937
+ */
7938
+ export declare const modalAllowProps: {
7939
+ readonly 'data-wave-focus-trap-allow': "";
7940
+ };
7941
+
7801
7942
  /**
7802
7943
  * Why a Dialog or Drawer asks to open or close: `trigger` (its Trigger part), `close` (a
7803
7944
  * `.Close` part), `close-button` (the built-in Close button), `escape`, `outside-press` (the
@@ -9159,7 +9300,7 @@ export declare type PolymorphicProps<C extends React_2.ElementType, OwnProps> =
9159
9300
  * </Popover>
9160
9301
  */
9161
9302
  export declare const Popover: {
9162
- ({ open: openProp, defaultOpen, onOpenChange, side, align, ignoreOutsideRefs, openOnHover, openDelay, closeDelay, openOnContext, target, children, }: PopoverProps): React_2.JSX.Element;
9303
+ ({ open: openProp, defaultOpen, onOpenChange, side, align, ignoreOutsideRefs, openOnHover, openDelay, closeDelay, openOnContext, target: targetProp, positioning, children, }: PopoverProps): React_2.JSX.Element;
9163
9304
  displayName: string;
9164
9305
  } & {
9165
9306
  Trigger: {
@@ -9316,10 +9457,18 @@ export declare interface PopoverProps {
9316
9457
  * `aria-labelledby`, and give a toggle button you use as the target `aria-haspopup="dialog"`,
9317
9458
  * `aria-expanded` and `aria-controls` yourself. A press on a target element does not close the
9318
9459
  * popover, and Tab from it enters the content when there is no trigger. Hold the element in
9319
- * state (a ref cannot be observed; TeachingPopover's `target` also takes a ref). A popover
9460
+ * state, or pass a ref object (read after each render of the popover, so an element that attaches without it rendering is noticed on its next render). A popover
9320
9461
  * opened by `openOnContext` is placed at the gesture instead.
9321
9462
  */
9322
- target?: PopupTarget;
9463
+ target?: PopupTargetInput;
9464
+ /**
9465
+ * Advanced positioning (Fluent's `positioning`): `offset` (px from the anchor), `fitViewport`
9466
+ * (limit the content to the space the viewport leaves; Fluent's `autoSize`), `matchReferenceWidth`,
9467
+ * `fallbackPlacements` (tried in order when the requested side has no room) and `target` (used
9468
+ * when the `target` prop is not set). `side` and `align` stay separate props.
9469
+ * @default `{ offset: 8 }`
9470
+ */
9471
+ positioning?: PopupPositioning;
9323
9472
  /** `Popover.Trigger` and `Popover.Content`. */
9324
9473
  children: React_2.ReactNode;
9325
9474
  }
@@ -9404,6 +9553,39 @@ export declare interface PopoverTriggerProps extends Omit<React_2.HTMLAttributes
9404
9553
  /** Alignment of a popup along the anchor's edge. */
9405
9554
  export declare type PopupAlign = 'start' | 'center' | 'end';
9406
9555
 
9556
+ /** A placement for `PopupPositioning.fallbackPlacements`: a side, and optionally an alignment on it. */
9557
+ export declare interface PopupPlacement {
9558
+ /** Side of the anchor. `start` and `end` follow the writing direction. */
9559
+ side: PopupSide;
9560
+ /** Alignment along that side. @default the surface's own `align` */
9561
+ align?: PopupAlign;
9562
+ }
9563
+
9564
+ /**
9565
+ * The advanced positioning options of a popup (the `positioning` prop; Fluent's `positioning`).
9566
+ * `side` and `align` stay separate props of each component, so every option has one source.
9567
+ */
9568
+ export declare interface PopupPositioning {
9569
+ /** Distance from the anchor in px. @default the component's own (Popover 8, Tooltip 8, TeachingPopover 12, listboxes 4) */
9570
+ offset?: number;
9571
+ /**
9572
+ * Limit the surface to the space the viewport leaves (Fluent's `autoSize`). Popover also scrolls
9573
+ * its content inside its border; the other surfaces only limit their size (their own lists and
9574
+ * grids scroll as they always did).
9575
+ * @default the component's own
9576
+ */
9577
+ fitViewport?: boolean;
9578
+ /** Make the surface as wide as its anchor. @default the component's own */
9579
+ matchReferenceWidth?: boolean;
9580
+ /** Placements to try, in order, when the requested side has no room; replaces the opposite side. */
9581
+ fallbackPlacements?: readonly PopupPlacement[];
9582
+ /** Position against this instead of the trigger. */
9583
+ target?: PopupTargetInput;
9584
+ }
9585
+
9586
+ /** {@link PopupPositioning} without `target`: the options of a popup that has no `target` prop. */
9587
+ export declare type PopupPositioningOptions = Omit<PopupPositioning, 'target'>;
9588
+
9407
9589
  /** A rectangle in viewport coordinates, as `getBoundingClientRect()` returns it (a `DOMRect` is one). */
9408
9590
  export declare interface PopupRect {
9409
9591
  x: number;
@@ -9423,12 +9605,20 @@ export declare interface PopupRect {
9423
9605
  export declare type PopupSide = 'top' | 'bottom' | 'start' | 'end' | 'left' | 'right';
9424
9606
 
9425
9607
  /**
9426
- * Where a popup is placed instead of next to its trigger (`Menu.Popover` and `Popover` `target`):
9427
- * an element held in state, or a `VirtualElement`. TeachingPopover's `target` (0.6) also takes a
9428
- * ref and no `VirtualElement`; ROADMAP P7-01 unifies them.
9608
+ * Where a popup is placed instead of next to its trigger (`Menu.Popover`, `Popover` and
9609
+ * `TeachingPopover` `target`): an element held in state, or a `VirtualElement`. Those components
9610
+ * also take a ref object (`PopupPositioning['target']`).
9429
9611
  */
9430
9612
  export declare type PopupTarget = HTMLElement | VirtualElement | null;
9431
9613
 
9614
+ /**
9615
+ * What a popup's `target` prop accepts: a {@link PopupTarget}, or a ref object (an element that
9616
+ * attaches without the popup rendering is read after each render of the popup).
9617
+ */
9618
+ export declare type PopupTargetInput = PopupTarget | {
9619
+ readonly current: HTMLElement | null;
9620
+ };
9621
+
9432
9622
  /**
9433
9623
  * Renders its children into `document.body` (or the WaveProvider `portalContainer`), wrapped in a
9434
9624
  * `<div class="wave-portal …">` that carries the provider's theme classes, direction and font, so
@@ -9485,6 +9675,16 @@ export declare interface PortalProps {
9485
9675
  ref?: React_2.Ref<HTMLDivElement>;
9486
9676
  }
9487
9677
 
9678
+ /** What {@link UsePopupPositionOptions.onPositioned} receives. */
9679
+ export declare interface PositionedInfo {
9680
+ /** Final placement after flipping, e.g. `'top-start'`. */
9681
+ placement: string;
9682
+ /** Final physical side after flipping. */
9683
+ side: 'top' | 'bottom' | 'left' | 'right';
9684
+ /** Always `true`: the callback runs once a position exists. */
9685
+ isPositioned: boolean;
9686
+ }
9687
+
9488
9688
  /**
9489
9689
  * Shows and hides its child with CSS enter and exit motion: the child stays mounted while its exit
9490
9690
  * motion runs, `inert` and marked `data-presence="exiting"`, and unmounts when it ends (at once
@@ -12839,6 +13039,13 @@ export declare interface TagPickerProps extends Omit<React_2.HTMLAttributes<HTML
12839
13039
  * option list keeps its size.
12840
13040
  */
12841
13041
  size?: TagPickerSize;
13042
+ /**
13043
+ * Advanced positioning of the popup (Fluent's `positioning`): `offset`, `fitViewport`,
13044
+ * `matchReferenceWidth` and `fallbackPlacements` (tried in order when the requested side has no
13045
+ * room). The popup opens below the field.
13046
+ * @default `{ matchReferenceWidth: true, fitViewport: true }`
13047
+ */
13048
+ positioning?: PopupPositioningOptions;
12842
13049
  /**
12843
13050
  * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),
12844
13051
  * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible
@@ -12974,7 +13181,9 @@ export declare type TagSize = Extract<Size, 'extra-small' | 'small' | 'medium'>;
12974
13181
  * - With `target`, the popover is portaled and positioned next to that element with a beak (it
12975
13182
  * inherits the surface colors); it stays hidden while the target is `null`, not positioned yet or
12976
13183
  * no longer mounted (a ref target is read after each render of the popover; see `target`).
12977
- * - With `target`, the keyboard order treats the popover as if it followed the target: Tab past
13184
+ * - With a `VirtualElement` target there is no element to follow: the popover keeps the place of
13185
+ * its portal in the keyboard order.
13186
+ * - With an element or ref `target`, the keyboard order treats the popover as if it followed the target: Tab past
12978
13187
  * its last button continues after the target, Shift+Tab from its first button (or from the
12979
13188
  * popover itself) returns to the target (for a target outside the Tab order, to the last control
12980
13189
  * inside it, else to the control before it), Tab from there enters the popover, and Shift+Tab
@@ -12986,7 +13195,7 @@ export declare type TagSize = Extract<Size, 'extra-small' | 'small' | 'medium'>;
12986
13195
  * it.
12987
13196
  */
12988
13197
  export declare const TeachingPopover: {
12989
- ({ steps, activeStep: activeStepProp, defaultActiveStep, currentStep, defaultCurrentStep, onStepChange, onDismiss, open: openProp, defaultOpen, onOpenChange, closeLabel, labels, target, side, align, className, style, onKeyDown, ref, ...rest }: TeachingPopoverProps): React_2.JSX.Element | null;
13198
+ ({ steps, activeStep: activeStepProp, defaultActiveStep, currentStep, defaultCurrentStep, onStepChange, onDismiss, open: openProp, defaultOpen, onOpenChange, closeLabel, labels, target: targetProp, positioning, side, align, className, style, onKeyDown, ref, ...rest }: TeachingPopoverProps): React_2.JSX.Element | null;
12990
13199
  displayName: string;
12991
13200
  };
12992
13201
 
@@ -13071,7 +13280,8 @@ export declare interface TeachingPopoverProps extends React_2.HTMLAttributes<HTM
13071
13280
  */
13072
13281
  labels?: TeachingPopoverLabels;
13073
13282
  /**
13074
- * The element the popover points at (a ref or the element). When given, the popover is
13283
+ * The element the popover points at (a ref, the element, or a `VirtualElement`: a rectangle such as a
13284
+ * point; an inline object is fine). When given, the popover is
13075
13285
  * rendered in a portal, positioned next to it with a beak, and flips or shifts to stay in view;
13076
13286
  * without it (`undefined`) the popover renders inline where it is placed (0.4 behaviour).
13077
13287
  * While the target is `null` or has not been positioned against yet (an element held in state
@@ -13092,7 +13302,7 @@ export declare interface TeachingPopoverProps extends React_2.HTMLAttributes<HTM
13092
13302
  * attached hides the popover right after that commit. Pass the element held in state when the
13093
13303
  * target can mount or unmount without the popover re-rendering.
13094
13304
  */
13095
- target?: React_2.RefObject<HTMLElement | null> | HTMLElement | null;
13305
+ target?: React_2.RefObject<HTMLElement | null> | HTMLElement | VirtualElement | null;
13096
13306
  /** Side of the `target` to open on; `start`/`end` follow the writing direction.
13097
13307
  * @default 'bottom'
13098
13308
  */
@@ -13101,6 +13311,13 @@ export declare interface TeachingPopoverProps extends React_2.HTMLAttributes<HTM
13101
13311
  * @default 'center'
13102
13312
  */
13103
13313
  align?: PopupAlign;
13314
+ /**
13315
+ * Advanced positioning (Fluent's `positioning`): `offset`, `fitViewport`, `matchReferenceWidth`,
13316
+ * `fallbackPlacements` and `target` (used when the `target` prop is not set). `side` and `align`
13317
+ * stay separate props.
13318
+ * @default `{ offset: 12 }`
13319
+ */
13320
+ positioning?: PopupPositioning;
13104
13321
  /** Ref to the popover surface (`role="dialog"`). */
13105
13322
  ref?: React_2.Ref<HTMLDivElement>;
13106
13323
  }
@@ -13390,6 +13607,13 @@ export declare interface TimePickerProps extends Omit<React_2.HTMLAttributes<HTM
13390
13607
  * list keeps its size.
13391
13608
  */
13392
13609
  size?: CoreSize;
13610
+ /**
13611
+ * Advanced positioning of the popup (Fluent's `positioning`): `offset`, `fitViewport`,
13612
+ * `matchReferenceWidth` and `fallbackPlacements` (tried in order when the requested side has no
13613
+ * room). The popup opens below the field.
13614
+ * @default `{ matchReferenceWidth: true, fitViewport: true }`
13615
+ */
13616
+ positioning?: PopupPositioningOptions;
13393
13617
  /**
13394
13618
  * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),
13395
13619
  * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible
@@ -14319,7 +14543,7 @@ export declare interface ToolbarToggleButtonProps extends Omit<ToggleButtonProps
14319
14543
  * </Menu>
14320
14544
  */
14321
14545
  export declare const Tooltip: {
14322
- ({ content, appearance: appearanceProp, variant, openDelay: openDelayProp, closeDelay, delay, open: openProp, defaultOpen, onOpenChange, relationship, side, align, children, className, onMouseEnter, onMouseLeave, onFocus, onBlur, ref, ...rest }: TooltipProps): React_2.JSX.Element;
14546
+ ({ content, appearance: appearanceProp, variant, openDelay: openDelayProp, closeDelay, delay, open: openProp, defaultOpen, onOpenChange, relationship, side, align, positioning, children, className, onMouseEnter, onMouseLeave, onFocus, onBlur, ref, ...rest }: TooltipProps): React_2.JSX.Element;
14323
14547
  displayName: string;
14324
14548
  };
14325
14549
 
@@ -14395,6 +14619,13 @@ export declare interface TooltipProps extends Omit<React_2.HTMLAttributes<HTMLSp
14395
14619
  * @default 'center'
14396
14620
  */
14397
14621
  align?: PopupAlign;
14622
+ /**
14623
+ * Advanced positioning (Fluent's `positioning`): `offset`, `fitViewport`, `matchReferenceWidth`
14624
+ * and `fallbackPlacements`. `side` and `align` stay separate props. The hover bridge across the
14625
+ * gap covers the default 8px, so a larger `offset` leaves a gap the pointer cannot cross.
14626
+ * @default `{ offset: 8 }`
14627
+ */
14628
+ positioning?: PopupPositioningOptions;
14398
14629
  /**
14399
14630
  * A single element that triggers the tooltip on hover and focus: it receives the
14400
14631
  * `aria-describedby`/`aria-labelledby`, plus any `id` and `aria-*` props given to the Tooltip
@@ -14817,6 +15048,82 @@ export declare function useAnnounce(): (message: string, politeness?: Politeness
14817
15048
  */
14818
15049
  export declare function useControllable<T>(controlledValue: T | undefined, defaultValue: T, onChange?: (value: T) => void): [value: T, setValue: SetValue<T>, isControlled: boolean];
14819
15050
 
15051
+ /**
15052
+ * Registers an open overlay surface as a **dismiss layer** in the shared layer stack and closes it
15053
+ * on Escape, outside presses and (optionally) focus leaving it — with correct nesting:
15054
+ *
15055
+ * - **Escape** (document `keydown`, bubble phase) is routed by focus location: the innermost layer
15056
+ * whose tree contains the event target or the focused element is the scope, and the topmost
15057
+ * escape-enabled layer of that scope's subtree handles it — so a tooltip or popover opened from
15058
+ * the focused dialog closes before the dialog, while an unrelated layer opened later does not
15059
+ * steal the key. With no escape-enabled layer there, an escape-enabled ancestor handles it; when
15060
+ * no layer contains the focus (or none of those takes Escape), the global topmost
15061
+ * escape-enabled one. Layers stacked below the topmost **isolating** modal (a Dialog/Drawer
15062
+ * whose `useModalIsolation` is active — its ancestors and older siblings) never take Escape, so
15063
+ * a modal that ignores Escape blocks it whether it is nested in a dialog or opened beside it.
15064
+ * A layer with `escape: 'inside'` (a non-modal Dialog or Drawer) takes Escape only while the
15065
+ * event target or the focused element is in its tree, so an Escape typed on the page leaves it
15066
+ * open and goes to the layers below it.
15067
+ * The handler calls `preventDefault()`. Events whose default is already prevented (an inner
15068
+ * widget consumed Escape) and IME composition events are ignored.
15069
+ * - **Outside press**: on `pointerdown` (capture) every open layer whose tree does not contain the
15070
+ * target is recorded; on the following `click` each recorded layer whose tree still does not
15071
+ * contain the click target is dismissed (children first). A drag from inside to outside never
15072
+ * dismisses, clicks inside nested portaled layers count as inside, a popup opened by the same
15073
+ * click survives, and an external toggle works. Layers stacked below the topmost isolating modal
15074
+ * are inert and never dismissed by presses on that modal or its backdrop; a `kind: 'modal'`
15075
+ * layer without isolation (the DatePicker calendar) shields nothing, so a page click closes it
15076
+ * and the layers around it. The pending press survives modifier keys (Shift/Ctrl+click) and
15077
+ * ends on Enter/Space, on `pointercancel`, or when no click follows a mouse `pointerup` in the
15078
+ * same task; touch and pen presses are kept until their click, which the browser dispatches
15079
+ * from a separate tap gesture.
15080
+ * - **Focus outside** (`focusOutside: true`): dismisses when focus moves outside the layer's tree.
15081
+ * That is decided in a microtask, once the current commit has run: an `autoFocus` field of a
15082
+ * popover, dialog or plain portal opened inside the layer gets focus before that surface's
15083
+ * portal and layer register, and keeps the layer open. Focus that is back inside the tree by
15084
+ * then keeps it open too.
15085
+ *
15086
+ * A layer's tree is its `refs`, the portal wrappers rendered inside it, its descendant layers and
15087
+ * the `[data-wave-focus-trap-allow]` regions (toasts). Parentage follows the React tree: wrap the surface in
15088
+ * `Portal layerId={layerId}` (or {@link DismissLayerProvider}) so layers opened inside it become
15089
+ * its children.
15090
+ *
15091
+ * @example
15092
+ * const { layerId } = useDismiss({ open, onDismiss: () => setOpen(false), refs: [surfaceRef, triggerRef], anchorRef: triggerRef });
15093
+ * return open && <Portal layerId={layerId}><div ref={surfaceRef}>…</div></Portal>;
15094
+ */
15095
+ export declare function useDismiss(options: UseDismissOptions): DismissLayer;
15096
+
15097
+ /** Options of {@link useDismiss}. */
15098
+ export declare interface UseDismissOptions {
15099
+ /** Whether the layer is open; the layer is registered only while `true`. */
15100
+ open: boolean;
15101
+ /** Called when the layer should close (the component sets its `open` state to `false`). */
15102
+ onDismiss: (reason: DismissReason, event: Event) => void;
15103
+ /**
15104
+ * Elements that belong to the layer: the content surface, the trigger/anchor and any extra
15105
+ * targets that must not count as "outside" (read at event time).
15106
+ */
15107
+ refs: ReadonlyArray<React_2.RefObject<HTMLElement | null>>;
15108
+ /** The trigger; focus traps leave a descendant layer through it (Tab → the element after it). */
15109
+ anchorRef?: React_2.RefObject<HTMLElement | null>;
15110
+ /** @default 'popover' */
15111
+ kind?: LayerKind;
15112
+ /**
15113
+ * Whether Escape dismisses the layer: always (`true`), never (`false`), or only while the key's
15114
+ * target or the focused element is in the layer's tree (`'inside'`).
15115
+ * @default true
15116
+ */
15117
+ escape?: boolean | 'inside';
15118
+ /**
15119
+ * Whether a press outside the layer's tree dismisses it. A predicate receives the `pointerdown`
15120
+ * event; returning `false` ignores that press. @default true
15121
+ */
15122
+ outsidePress?: boolean | ((event: PointerEvent | MouseEvent) => boolean);
15123
+ /** Whether focus moving outside the layer's tree dismisses it (listboxes). @default false */
15124
+ focusOutside?: boolean;
15125
+ }
15126
+
14820
15127
  /**
14821
15128
  * Returns a callback with a stable identity that always invokes the latest `fn` passed to the hook.
14822
15129
  * Use it for handlers read by effects or passed to memoised children, so neither re-runs when the
@@ -14891,6 +15198,172 @@ export declare interface UseFieldControlOptions {
14891
15198
  nativeRequired?: boolean;
14892
15199
  }
14893
15200
 
15201
+ /**
15202
+ * A focusable group (Fluent's `useFocusableGroup`, tabster's groupper): one tab stop that holds
15203
+ * several focusable elements, so a long list of rich rows does not cost a Tab press per control.
15204
+ * With `tabBehavior: 'limited'` or `'limited-trap-focus'`, Tab skips the elements inside while focus
15205
+ * is on the group element itself, and Shift+Tab from outside lands on the group element instead of
15206
+ * its last element; Enter or F2 enters the group, and Escape leaves it. A group is entered while
15207
+ * focus is on an element inside it, however it got there (a click, a popup returning focus, a
15208
+ * script). No tabindex is rewritten: components with their own tab stops (Toolbar, TabList) work
15209
+ * inside a group. A key from a popup portaled out of the group, a key that belongs to a nested
15210
+ * group and a key an inner element already handled (`preventDefault()`, as an input consuming
15211
+ * Escape does) are left alone.
15212
+ *
15213
+ * @example
15214
+ * const { groupProps } = useFocusableGroup({ tabBehavior: 'limited' });
15215
+ * <li role="group" aria-label="Message" {...groupProps}>
15216
+ * <button>Reply</button> <button>Forward</button>
15217
+ * </li>
15218
+ */
15219
+ export declare function useFocusableGroup(options?: UseFocusableGroupOptions): UseFocusableGroupResult;
15220
+
15221
+ /** Options of {@link useFocusableGroup}. */
15222
+ export declare interface UseFocusableGroupOptions {
15223
+ /**
15224
+ * How the group treats the elements inside it (Fluent's `tabBehavior`):
15225
+ *
15226
+ * - `'unlimited'`: the group is one more tab stop and the elements inside it stay reachable by
15227
+ * Tab; no key is intercepted.
15228
+ * - `'limited'`: the group is one tab stop, in both directions. Enter or F2 on it moves focus to
15229
+ * its first tabbable element, Tab and Shift+Tab then move between the elements inside, Tab
15230
+ * past the last one leaves the group, and Escape returns focus to the group.
15231
+ * - `'limited-trap-focus'`: as `'limited'`, but Tab past the last element wraps to the first and
15232
+ * Shift+Tab before the first wraps to the last, until Escape.
15233
+ *
15234
+ * @default 'unlimited'
15235
+ */
15236
+ tabBehavior?: FocusableGroupTabBehavior;
15237
+ }
15238
+
15239
+ /** Result of {@link useFocusableGroup}. */
15240
+ export declare interface UseFocusableGroupResult {
15241
+ /** Spread onto the group element. */
15242
+ groupProps: FocusableGroupProps;
15243
+ }
15244
+
15245
+ /**
15246
+ * Keeps keyboard focus inside `container` while `enabled` (modal dialogs, drawers, the DatePicker
15247
+ * calendar). Element-based: pass the surface held in state via a callback ref, so the trap starts
15248
+ * when the element appears.
15249
+ *
15250
+ * - **Initial focus** runs synchronously in the commit in which the container appears (no
15251
+ * `requestAnimationFrame`), and does nothing when focus is already inside (an `autoFocus`
15252
+ * element wins).
15253
+ * - **Tab / Shift+Tab** are handled by a document bubble-phase `keydown` listener that ignores
15254
+ * events whose default is already prevented, so a React handler inside (a menu closing on Tab, a
15255
+ * grid) can take the key first. Focus wraps at the edges, and from the container itself or a
15256
+ * non-tabbable element it continues in document order. Tabbable elements are computed on every
15257
+ * keydown (content may change; radio-group stops depend on focus), never cached.
15258
+ * - Tabbables inside `[data-wave-focus-trap-allow]` regions (the Toaster viewport) join the cycle.
15259
+ * - **Descendant layers** (a popover or menu opened from inside, identified through `layerId`):
15260
+ * Tab moves natively inside them; leaving one moves focus to the element after its anchor
15261
+ * (Shift+Tab: the anchor itself). Inside a plain `<Portal>` rendered in the surface (no layer,
15262
+ * no anchor) Tab is native too; leaving it wraps to the first (Shift+Tab: last) element. A
15263
+ * layer's trigger (its anchor, or an element around it such as a tooltip's wrapper) belongs to
15264
+ * the region it sits in, so Tab from an open info button or a button showing its tooltip moves
15265
+ * on as from any other element of that portal or popover.
15266
+ * - Focus that lands outside (not in the container, an allowed region or a descendant layer)
15267
+ * returns to the last focused element inside, also when that outside element loses it again
15268
+ * (removed or blurred, leaving focus on `<body>`). That is decided in a microtask, once the
15269
+ * current commit has run: an `autoFocus` element of a surface opened above the trap (a nested or
15270
+ * stacked dialog, a popover opened from the surface) gets focus before that surface's layer and
15271
+ * trap exist, and keeps it. The layer's own `refs` (its trigger, outside the container) are
15272
+ * outside: opening from the focused trigger still moves focus in, and focus moving back onto
15273
+ * the trigger is returned. Focus pulled out again while it is being returned (another focus
15274
+ * trap on the page) is left there.
15275
+ * - Traps form a stack (shared through the global registry): only the topmost acts.
15276
+ */
15277
+ export declare function useFocusTrap(container: HTMLElement | null, options: UseFocusTrapOptions): void;
15278
+
15279
+ /** Options of {@link useFocusTrap}. */
15280
+ export declare interface UseFocusTrapOptions {
15281
+ /** Whether the trap is active. */
15282
+ enabled: boolean;
15283
+ /**
15284
+ * The surface's dismiss layer; focus inside its descendant layers (portaled popovers opened from
15285
+ * inside) is allowed. The layer's own `refs` outside the container (its trigger) are not.
15286
+ */
15287
+ layerId?: string;
15288
+ /**
15289
+ * What to focus when the trap starts, unless focus is already inside (an `autoFocus` element
15290
+ * wins). @default 'first' (the first tabbable element, else the container)
15291
+ */
15292
+ initialFocus?: React_2.RefObject<HTMLElement | null> | 'first' | 'container' | (() => HTMLElement | null);
15293
+ /** Regions outside the container whose tabbables join the Tab cycle. @default '[data-wave-focus-trap-allow]' (the regions marked with `modalAllowProps`) */
15294
+ allowOutsideSelector?: string;
15295
+ }
15296
+
15297
+ /**
15298
+ * Whether the page is in keyboard-navigation mode: `true` after the last input was a key press
15299
+ * (any key but a lone modifier), `false` after a pointer or touch press and before any input. For
15300
+ * logic that needs the mode in script, such as showing a focus cue in a widget that draws its own;
15301
+ * plain focus rings should keep using the `focus-visible` variant. One set of document listeners
15302
+ * serves every caller and goes away with the last one. `false` on the server and during
15303
+ * hydration.
15304
+ *
15305
+ * @example
15306
+ * const keyboard = useFocusVisible();
15307
+ * return <div data-keyboard={keyboard ? '' : undefined}>…</div>;
15308
+ */
15309
+ export declare function useFocusVisible(): boolean;
15310
+
15311
+ /**
15312
+ * Grid keyboard model of the APG Grid pattern for a `<table role="grid">` (DataGrid).
15313
+ *
15314
+ * - **One tab stop.** Exactly one cell of the grid is in the tab order (initially the first cell).
15315
+ * Its focus target is its only focusable widget when that widget is not a text-entry control
15316
+ * (a checkbox, a sort button, a link); otherwise — no widget, several widgets, a text-entry
15317
+ * control or a nested composite — the cell itself. An unchecked radio whose named group has a
15318
+ * checked radio is not a target either (browsers skip it in the Tab order), so its cell is.
15319
+ * Every other cell and every widget inside a cell gets `tabindex="-1"`. Rows are never focusable.
15320
+ * When a widget becomes the target of the focused cell (Space on the cell checks its radio), the
15321
+ * cell keeps focus and the tab stop (removing its `tabindex` would blur it) while its target stays
15322
+ * at `tabindex="-1"`; the target takes the tab stop once the cell is blurred.
15323
+ * - **Navigation mode** (focus on a cell or on its target widget): ArrowLeft/ArrowRight (the
15324
+ * previous/next cell of the row, mirrored in RTL), ArrowUp/ArrowDown, Home/End (first/last cell
15325
+ * of the row), Ctrl+Home/Ctrl+End (first cell of the grid / last cell of the last row) and
15326
+ * PageUp/PageDown ({@link UseGridNavigationOptions.pageSize} rows) move focus between cells.
15327
+ * ArrowUp/ArrowDown and PageUp/PageDown keep the visual column (`colSpan` and `rowSpan` counted,
15328
+ * so a grouped header works), clamped to a shorter row. Space and Enter on a target widget reach
15329
+ * the widget.
15330
+ * - **Interaction mode**: Enter or F2 on a cell that is its own target moves focus into its first
15331
+ * widget; clicking a widget that is not the cell's target (a text input) enters it too. The
15332
+ * grid keys are then ignored, so the arrow keys move the caret, and Tab moves between the cell's
15333
+ * widgets. Escape returns focus to the cell. Leaving the grid ends interaction mode.
15334
+ * - **Nested composites** (an element with `data-roving-container` or role toolbar, radiogroup,
15335
+ * listbox, grid, treegrid, tablist, menu, menubar or tree) count as one widget that uses the arrow
15336
+ * keys: its cell takes focus, and Enter/F2 enters the composite at its own tab stop. The grid never
15337
+ * writes `tabindex` on or inside a composite (the composite manages its own), so a composite
15338
+ * keeps its own Tab stop — the same documented limitation as `useRovingTabIndex`.
15339
+ *
15340
+ * Keys are ignored when the event's default was prevented (a widget that handled the key, a
15341
+ * consumer handler), or with Alt/Meta held. The tab indexes are written to the DOM (layout effect
15342
+ * plus a `MutationObserver`), so rows and widgets added later are covered without a re-render. Focus
15343
+ * moves re-sync only the cells involved, the observer only the cells that changed, and the grid's
15344
+ * own `tabindex` writes do not trigger a re-sync.
15345
+ *
15346
+ * Internal to the table package.
15347
+ */
15348
+ export declare function useGridNavigation(options?: UseGridNavigationOptions): UseGridNavigationResult;
15349
+
15350
+ /** Options of {@link useGridNavigation}. */
15351
+ export declare interface UseGridNavigationOptions {
15352
+ /**
15353
+ * How many rows PageUp and PageDown move focus.
15354
+ * @default 10
15355
+ */
15356
+ pageSize?: number;
15357
+ }
15358
+
15359
+ /** Result of {@link useGridNavigation}. */
15360
+ export declare interface UseGridNavigationResult {
15361
+ /** Callback ref for the `<table role="grid">` element. Stable identity. */
15362
+ gridRef: React_2.RefCallback<HTMLTableElement>;
15363
+ /** Keyboard and focus handlers for the grid element. Stable identities. */
15364
+ gridProps: GridNavigationHandlers;
15365
+ }
15366
+
14894
15367
  /**
14895
15368
  * Generates a stable, SSR-safe unique id, optionally with a prefix. Wraps React's `useId` so every
14896
15369
  * component builds DOM ids the same way (C-IDS).
@@ -14906,6 +15379,26 @@ export declare interface UseFieldControlOptions {
14906
15379
  */
14907
15380
  export declare function useId(prefix?: string): string;
14908
15381
 
15382
+ /**
15383
+ * The trap's initial focus without the trap (a non-modal Dialog or Drawer, which moves focus in
15384
+ * when it opens but does not keep it there): in the layout phase of the commit in which
15385
+ * `enabled && container` becomes true, does nothing when focus is already inside the container or
15386
+ * one of the layer's descendant layers (an `autoFocus` element wins), else focuses
15387
+ * `initialFocus` (default: the first tabbable element), else the container. `useFocusTrap` runs
15388
+ * the same code when it starts. It adds no listener.
15389
+ */
15390
+ export declare function useInitialFocus(container: HTMLElement | null, options: UseInitialFocusOptions): void;
15391
+
15392
+ /** Options of {@link useInitialFocus}. */
15393
+ export declare interface UseInitialFocusOptions {
15394
+ /** Whether the surface is open: focus moves in when it becomes `true` with a container. */
15395
+ enabled: boolean;
15396
+ /** The surface's dismiss layer: focus already in one of its descendant layers stays there. */
15397
+ layerId?: string;
15398
+ /** What to focus first. @default 'first' (the first tabbable element, else the container) */
15399
+ initialFocus?: UseFocusTrapOptions['initialFocus'];
15400
+ }
15401
+
14909
15402
  /**
14910
15403
  * `false` on the server and during hydration, `true` in every other client render — including the
14911
15404
  * first render of a component mounted on the client, so no second commit is needed.
@@ -15241,6 +15734,11 @@ export declare interface UseListboxPopupOptions {
15241
15734
  * `setReference` too (merged into its ref), which places the surface against it.
15242
15735
  */
15243
15736
  anchorRef: React_2.RefObject<HTMLElement | null>;
15737
+ /**
15738
+ * Advanced positioning: `offset`, `fitViewport`, `matchReferenceWidth` and `fallbackPlacements`.
15739
+ * @default `{ matchReferenceWidth: true, fitViewport: true }`
15740
+ */
15741
+ positioning?: PopupPositioningOptions;
15244
15742
  }
15245
15743
 
15246
15744
  /**
@@ -15358,6 +15856,84 @@ export declare interface UseListboxResult {
15358
15856
  */
15359
15857
  export declare function useMergedRefs<T>(...refs: Array<React_2.Ref<T> | undefined | null>): React_2.RefCallback<T>;
15360
15858
 
15859
+ /**
15860
+ * Everything a modal surface (Dialog, Drawer) needs, composed in the order that works:
15861
+ *
15862
+ * 1. `useDismiss({ kind: 'modal' })` — Escape and outside presses (the backdrop is outside the
15863
+ * content surface, so a click on it dismisses; a drag from the content does not).
15864
+ * 2. `useFocusTrap` — initial focus, Tab cycle incl. toasts and descendant layers.
15865
+ * 3. `useModalIsolation` — the rest of the page is `inert` (instead of `aria-modal`).
15866
+ * 4. `useScrollLock` — ref-counted page scroll lock.
15867
+ * 5. `useRestoreFocus` — the opener (or `triggerRef`/`finalFocusRef`) gets focus back.
15868
+ *
15869
+ * On close the trap is released before the isolation is lifted, and the isolation is lifted
15870
+ * before focus is restored (an inert opener cannot take focus). Wrap the surface in
15871
+ * `Portal layerId={layerId}` so layers opened inside the modal become its descendants.
15872
+ *
15873
+ * `modalType: 'alert'` composes the same with `outsidePress: false`. `modalType: 'non-modal'`
15874
+ * registers a `dialog` layer (Escape only from inside its tree, no outside press, no focus-outside
15875
+ * dismissal), keeps the trap, the isolation and the scroll lock off, moves focus in on open with
15876
+ * the trap's initial-focus rule (`useInitialFocus`) and restores focus only when it is inside the
15877
+ * surface (or in a layer opened from it) at close, or was lost to `<body>` from there. Every hook
15878
+ * is always called and keys on `open`: a `modalType` that changes while open applies at once (the
15879
+ * trap, isolation and lock follow). It leaves focus inside the surface where it is; focus outside
15880
+ * it moves in, as on open: a switch to `modal` or `alert` starts the trap (the page turns inert),
15881
+ * and a switch to `non-modal` runs the initial focus (focus in the toast region, which a trap lets
15882
+ * in, moves into the surface). The Tab order of a non-modal surface (its place after the opener)
15883
+ * is the component's.
15884
+ *
15885
+ * A surface that mounts through the presence core (Dialog, Drawer) passes its open state as
15886
+ * `open`, never its mount (`isMounted`), and its element as `container` also while it is mounted
15887
+ * closed: the layer, the trap, the isolation and the scroll lock end and focus is restored in the
15888
+ * commit that closes it, while the element still runs its exit motion (`inert`) or stays mounted
15889
+ * (`hidden`, with `unmountOnClose={false}`); the next open starts them again with the same
15890
+ * element.
15891
+ */
15892
+ export declare function useModalLayer(options: UseModalLayerOptions): DismissLayer;
15893
+
15894
+ /**
15895
+ * Options of {@link useModalLayer}: `useDismiss` options (the kind follows `modalType`) plus focus.
15896
+ */
15897
+ export declare interface UseModalLayerOptions extends Omit<UseDismissOptions, 'kind'> {
15898
+ /** The modal surface, held in state via a callback ref. */
15899
+ container: HTMLElement | null;
15900
+ /**
15901
+ * `modal` (default) and `alert` register a `modal` layer, trap focus, isolate the page, lock its
15902
+ * scroll and restore focus (an `alert` layer ignores outside presses); `non-modal` registers a
15903
+ * `dialog` layer (`escape: 'inside'`, no outside press, no focus-outside), traps, isolates and
15904
+ * locks nothing, moves focus in on open with the trap's initial-focus rule and restores focus only
15905
+ * from inside (`requireFocusInside`).
15906
+ * @default 'modal'
15907
+ */
15908
+ modalType?: ModalType;
15909
+ /** What the focus trap (or a non-modal surface's initial focus) focuses first. @default 'first' */
15910
+ initialFocus?: UseFocusTrapOptions['initialFocus'];
15911
+ /** The trigger: preferred focus-restore target. */
15912
+ triggerRef?: React_2.RefObject<HTMLElement | null>;
15913
+ /** Consumer override for the focus-restore target. */
15914
+ finalFocusRef?: React_2.RefObject<HTMLElement | null>;
15915
+ }
15916
+
15917
+ /**
15918
+ * Whether a modal surface is open (a Dialog, an overlay Drawer, an alert, the DatePicker's calendar, or your
15919
+ * own `useDismiss({ kind: 'modal' })` layer): `true` from the
15920
+ * commit that opens it to the commit that closes it, not until its exit motion ends. A non-modal
15921
+ * Dialog or Drawer, a Popover or a Menu is no modal. `false` on the server and during hydration.
15922
+ *
15923
+ * Use it to hold back app behavior the modal should own, such as global keyboard shortcuts, instead
15924
+ * of guessing from the page's `inert` attributes.
15925
+ *
15926
+ * @example
15927
+ * const modalOpen = useModalOpen();
15928
+ * useEffect(() => {
15929
+ * if (modalOpen) return;
15930
+ * const onKey = (event: KeyboardEvent) => { if (event.key === '/') focusSearch(); };
15931
+ * document.addEventListener('keydown', onKey);
15932
+ * return () => document.removeEventListener('keydown', onKey);
15933
+ * }, [modalOpen]);
15934
+ */
15935
+ export declare function useModalOpen(): boolean;
15936
+
15361
15937
  /**
15362
15938
  * The items an {@link Overflow} currently hides: their `itemId`s in DOM order and their count. Use
15363
15939
  * it in the component that `overflowButton` renders to list the hidden items in a menu. Must be
@@ -15373,6 +15949,117 @@ export declare interface UseOverflowMenuResult {
15373
15949
  count: number;
15374
15950
  }
15375
15951
 
15952
+ /**
15953
+ * Positions a popup surface next to its anchor with `@floating-ui/react-dom` (Tooltip, Popover,
15954
+ * Menu, listboxes, the DatePicker calendar, TeachingPopover): `offset`, `flip`, `shift`, optional
15955
+ * `size` (reference width / available space as CSS variables) and `arrow`. `flip`, `shift` and
15956
+ * `size` keep the same viewport padding, taken from the `shift` option (8px by default). Logical
15957
+ * `start`/`end` sides follow `useDirection()` (the WaveProvider `dir`, else the document
15958
+ * direction), and so does start/end alignment.
15959
+ *
15960
+ * Positions update only while `open` (`autoUpdate` on scroll/resize; element resizes and layout
15961
+ * shifts only where `ResizeObserver`/`IntersectionObserver` exist). Spread `floatingProps` onto the
15962
+ * surface: `data-side`/`data-align` expose the final placement for styling (C-CLASS).
15963
+ *
15964
+ * The anchor is an element or a `VirtualElement` (a rectangle such as the pointer position; a new
15965
+ * object on every render is fine); give it a `contextElement` so scrolling its containers updates
15966
+ * the position. A virtual anchor reaches floating-ui through one stable proxy that reads the latest
15967
+ * object: a new object only recomputes the position (which renders only when the position
15968
+ * changes), and a new proxy is made only when the `contextElement` changes.
15969
+ *
15970
+ * Destructure the result: `eslint-plugin-react-hooks` (`react-hooks/refs`) treats an object
15971
+ * whose member is passed to a `ref` prop as a ref, and then rejects reading its other members
15972
+ * during render.
15973
+ *
15974
+ * @example
15975
+ * const { setReference, setFloating, floatingProps } = usePopupPosition({ open, side: 'bottom' });
15976
+ * <button ref={setReference} />
15977
+ * {open && <Portal><div ref={setFloating} {...floatingProps} /></Portal>}
15978
+ */
15979
+ export declare function usePopupPosition(options: UsePopupPositionOptions): UsePopupPositionResult;
15980
+
15981
+ /** Options of {@link usePopupPosition}. */
15982
+ export declare interface UsePopupPositionOptions {
15983
+ /** Whether the popup is open; positions are kept up to date only while `true`. */
15984
+ open: boolean;
15985
+ /** Side of the anchor. `start`/`end` follow the writing direction. @default 'bottom' */
15986
+ side?: PopupSide;
15987
+ /** Alignment along that side. @default 'start' */
15988
+ align?: PopupAlign;
15989
+ /** Distance from the anchor in px. @default 4 (tooltips use 8) */
15990
+ offset?: number;
15991
+ /** Flip to the opposite side when there is not enough room. @default true */
15992
+ flip?: boolean;
15993
+ /**
15994
+ * Shift along the side to stay inside the viewport. Its padding is also the viewport padding of
15995
+ * `flip` and of `size` (`fitViewport`, `matchReferenceWidth`): `true` means 8px, and `false`
15996
+ * lets the popup flip only once it touches the viewport edge and grow right up to it. With
15997
+ * `crossAxis: true` it also shifts across the side, over the anchor, when neither side has room
15998
+ * after `flip` (submenus), and `fitViewport` then offers the whole viewport in that direction.
15999
+ * @default { padding: 8 }
16000
+ */
16001
+ shift?: boolean | {
16002
+ padding: number;
16003
+ crossAxis?: boolean;
16004
+ };
16005
+ /** Make the surface as wide as the anchor (listboxes). @default false */
16006
+ matchReferenceWidth?: boolean;
16007
+ /** Limit the surface to the available space (`max-width`/`max-height`). @default false */
16008
+ fitViewport?: boolean;
16009
+ /** An arrow (beak) element inside the surface, positioned through `arrowStyles`. */
16010
+ arrowRef?: React_2.RefObject<HTMLElement | null>;
16011
+ /** CSS positioning strategy. @default 'fixed' */
16012
+ strategy?: 'absolute' | 'fixed';
16013
+ /**
16014
+ * Placements to try, in order, when the requested side has no room, instead of only the opposite
16015
+ * side. Ignored with `flip: false`. An omitted `align` is the hook's own `align`.
16016
+ */
16017
+ fallbackPlacements?: readonly PopupPlacement[];
16018
+ /**
16019
+ * Hide the surface (`visibility: hidden`: its layout is unaffected, but its content cannot take
16020
+ * focus, so a surface that holds focus loses it) while the anchor is scrolled out of view or
16021
+ * clipped away. @default false
16022
+ */
16023
+ hideWhenDetached?: boolean;
16024
+ /**
16025
+ * Called after the surface is positioned, and again whenever the final placement changes (a flip,
16026
+ * a fallback): not on every scroll or resize recompute. It runs from an effect, never during
16027
+ * render, and not while closed.
16028
+ */
16029
+ onPositioned?: (info: PositionedInfo) => void;
16030
+ }
16031
+
16032
+ /** Returned by {@link usePopupPosition}. */
16033
+ export declare interface UsePopupPositionResult {
16034
+ /**
16035
+ * Sets the anchor: a ref callback for the anchor (trigger) element, or a call from a layout
16036
+ * effect or an event. The anchor is an element or a `VirtualElement` (a rectangle such as the
16037
+ * pointer position; a new object on every render is fine); give it a `contextElement` so
16038
+ * scrolling its containers updates the position.
16039
+ */
16040
+ setReference(el: HTMLElement | VirtualElement | null): void;
16041
+ /** Ref callback for the popup surface. */
16042
+ setFloating(el: HTMLElement | null): void;
16043
+ /** Position styles for the surface (also in `floatingProps.style`). */
16044
+ floatingStyles: React_2.CSSProperties;
16045
+ /** Position styles for the arrow element. */
16046
+ arrowStyles: React_2.CSSProperties;
16047
+ /** Final placement after flipping, e.g. `'top-start'`. */
16048
+ placement: string;
16049
+ /** Final physical side after flipping. */
16050
+ side: 'top' | 'bottom' | 'left' | 'right';
16051
+ /** Whether a position has been computed since the popup opened. */
16052
+ isPositioned: boolean;
16053
+ /** Recomputes the position now, for a change floating-ui cannot observe. A no-op while closed. */
16054
+ update(): void;
16055
+ /** Spread onto the surface: `data-side`, `data-align` and the position style. */
16056
+ floatingProps: {
16057
+ 'data-side': string;
16058
+ 'data-align': string;
16059
+ style: React_2.CSSProperties;
16060
+ };
16061
+ }
16062
+
15376
16063
  /**
15377
16064
  * Mounts and unmounts an element with CSS enter and exit motion. Style the phases with
15378
16065
  * `data-presence` variants, e.g. `transition-opacity duration-wave-normal
@@ -15454,6 +16141,102 @@ export declare interface UsePresenceResult {
15454
16141
  presenceProps: PresenceAttributes;
15455
16142
  }
15456
16143
 
16144
+ /**
16145
+ * Returns focus to where it came from when a surface closes (dialogs, drawers, popovers, menus,
16146
+ * the DatePicker calendar, TeachingPopover).
16147
+ *
16148
+ * - **Capture**: when `enabled` flips to `true`, the opener is captured in an insertion effect —
16149
+ * before React applies `autoFocus` inside the new surface — preferring `triggerRef.current` and
16150
+ * ignoring `<body>` and elements inside `container`. When that finds nothing (a surface that
16151
+ * mounts open, before the refs of its commit are attached), it is captured again in the layout
16152
+ * phase of the same commit. Its place in the document and the triggers of the overlays it sits
16153
+ * in are recorded with it. When focus is already on `<body>` because
16154
+ * the focused element was removed earlier in the same commit (a menu item in a popover that
16155
+ * closes as the dialog it opens appears, the popover coming first in the tree), a document
16156
+ * focus tracker supplies that element with its recorded place and overlay triggers. The tracker
16157
+ * runs while any instance of the hook is mounted, and it forgets an element the user moved focus
16158
+ * away from on purpose.
16159
+ * - **Restore** when `enabled` flips to `false` (layout phase) and when the component unmounts
16160
+ * while enabled. The unmount restore runs in a microtask and is cancelled if the same instance
16161
+ * mounts again, so React StrictMode's simulated unmount does not pull focus out of a surface
16162
+ * that just opened.
16163
+ * - **Targets**, first valid wins:
16164
+ * 1. `finalFocusRef` → the captured opener → `triggerRef` → `fallback()`.
16165
+ * 2. When the opener was removed or cannot take focus, its replacement, nearest first: the
16166
+ * tabbable element next to where it was (in the innermost surviving ancestor that holds one,
16167
+ * the next one — the next row's action after a delete — else the previous one; then the same
16168
+ * one level up), else the trigger of the overlay it was in (a menu item's menu button), else
16169
+ * the element next to that trigger. When the surface is rendered inside another open layer
16170
+ * (its parent layer, from `DismissLayerContext`: a confirm Dialog in a Drawer's content),
16171
+ * only the replacements inside that layer's tree are tried here.
16172
+ * 3. The parent layer's surface, then the replacements outside the parent layer.
16173
+ * 4. The surface of the modal layer that stays open.
16174
+ *
16175
+ * So a confirm Dialog rendered in a Drawer's content and one rendered next to the Drawer both
16176
+ * return focus to the adjacent row, not to the Drawer's panel. A target is valid when it is
16177
+ * connected, focusable, not inside `[inert]` or `[aria-hidden="true"]`, and not cut off behind
16178
+ * another open modal layer — so focus never lands on the inert page behind a Drawer that stays
16179
+ * open, and is not dropped on `<body>` while a valid target exists. Focus uses `preventScroll`.
16180
+ * - `onlyIfFocusInside` (popovers): restores only when focus is inside the surface or was lost to
16181
+ * `<body>`.
16182
+ * - `requireFocusInside` (surfaces that do not trap focus: a non-modal Dialog or Drawer, an inline
16183
+ * Drawer): restores only when focus is inside the surface or in a layer opened from it (a
16184
+ * descendant layer of `layerId`, or a layer anchored inside the surface), or was lost to
16185
+ * `<body>` from an element in either; a close from code while focus is on `<body>` or on the
16186
+ * page moves nothing.
16187
+ * - `isHoverClose`: a close by the hover intent restores only when focus is inside the surface, so
16188
+ * a hover close never moves focus from `<body>` or from where the user put it. The same holds for
16189
+ * a surface opened from inside one that closes by hover (a submenu, a hover card in a hover
16190
+ * card): every mounted instance is known to the others through the focus tracker's record.
16191
+ */
16192
+ export declare function useRestoreFocus(options: UseRestoreFocusOptions): void;
16193
+
16194
+ /** Options of {@link useRestoreFocus}. */
16195
+ export declare interface UseRestoreFocusOptions {
16196
+ /** `true` while the surface is open. */
16197
+ enabled: boolean;
16198
+ /** The layer surface: opener candidates inside it are ignored. */
16199
+ container?: HTMLElement | null;
16200
+ /** The trigger: preferred restore target. */
16201
+ triggerRef?: React_2.RefObject<HTMLElement | null>;
16202
+ /** Consumer override: focused first when valid. */
16203
+ finalFocusRef?: React_2.RefObject<HTMLElement | null>;
16204
+ /** Used when neither the override, the opener nor the trigger can take focus. */
16205
+ fallback?: () => HTMLElement | null;
16206
+ /**
16207
+ * Popovers: restore only when focus was inside the surface (or lost to `<body>`) at close, so a
16208
+ * click that moved focus elsewhere is respected. @default false
16209
+ */
16210
+ onlyIfFocusInside?: boolean;
16211
+ /**
16212
+ * Read when the surface closes, or unmounts while open: `true` when the hover intent closed it
16213
+ * (Popover and Menu `openOnHover`, a submenu closing by hover). A hover close never moves focus:
16214
+ * it restores only while focus is inside the surface, so focus on `<body>` (where a hover-opened
16215
+ * surface leaves it) or elsewhere stays where it is. A surface opened from inside one that closes
16216
+ * by hover (its opener, else its trigger, lies in that surface: a submenu, a hover card in a
16217
+ * hover card, at any depth) is taken along, and its close counts as a hover close too. Every
16218
+ * other close keeps the rules above.
16219
+ */
16220
+ isHoverClose?: () => boolean;
16221
+ /**
16222
+ * Surfaces that do not trap focus (a non-modal Dialog or Drawer, an inline Drawer): restore only
16223
+ * when focus is inside the surface at close, or was lost to `<body>` from an element inside it
16224
+ * (removed, or made unable to take focus). Focus elsewhere, or on `<body>` for another reason
16225
+ * (nothing had focus, a press on a spot that takes no focus, a close from code), stays where it
16226
+ * is. Wins over `onlyIfFocusInside`. Focus in a layer opened from the surface (a Popover or a
16227
+ * confirm Dialog, portaled outside it) counts as inside: a descendant layer of `layerId`, or a
16228
+ * layer anchored to an element inside the surface; so does focus lost to `<body>` from one.
16229
+ * @default false
16230
+ */
16231
+ requireFocusInside?: boolean;
16232
+ /**
16233
+ * The surface's own dismiss layer, with `requireFocusInside`: focus in one of its descendant
16234
+ * layers counts as inside the surface, also after the surface's layer has unregistered (in the
16235
+ * commit that closes it).
16236
+ */
16237
+ layerId?: string;
16238
+ }
16239
+
15457
16240
  /**
15458
16241
  * Implements the WAI-ARIA roving tabindex pattern for composite widgets: one item holds the tab
15459
16242
  * stop (`tabIndex=0`, all others `-1`), arrow keys move focus between items, Home/End jump to the
@@ -15542,10 +16325,23 @@ export declare interface UseRovingTabIndexOptions {
15542
16325
  items?: readonly string[];
15543
16326
  /**
15544
16327
  * Arrow key axis: `'horizontal'` uses Left/Right (mirrored in RTL), `'vertical'` uses Up/Down,
15545
- * `'both'` uses all four.
16328
+ * `'both'` uses all four, in the DOM order of the items.
16329
+ *
16330
+ * `'grid'` is a two-dimensional grid: Left/Right move through the cells in reading order across
16331
+ * rows (mirrored in RTL); Up/Down go to the cell at the same index in the previous or next row,
16332
+ * else to the nearest enabled cell of that row (the earlier one on a tie), skipping rows without
16333
+ * an enabled cell, and stop at the first and last row; Home/End go to the first and last enabled
16334
+ * cell of the row, Ctrl+Home/End of the grid (whatever `homeEndKeys` says). Rows are the
16335
+ * `role="row"` elements inside the container, else groups of `columns` items in DOM order. Without
16336
+ * either, `'grid'` acts as `'both'` and a development warning says so.
15546
16337
  * @default 'horizontal'
15547
16338
  */
15548
- orientation?: 'horizontal' | 'vertical' | 'both';
16339
+ orientation?: 'horizontal' | 'vertical' | 'both' | 'grid';
16340
+ /**
16341
+ * With `orientation: 'grid'` and no `role="row"` elements: the number of cells per row. The last
16342
+ * row may be shorter.
16343
+ */
16344
+ columns?: number;
15549
16345
  /**
15550
16346
  * Whether arrow keys wrap around at the ends.
15551
16347
  * @default true