@radix-ng/primitives 1.0.9 → 1.0.10

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 (37) hide show
  1. package/fesm2022/radix-ng-primitives-autocomplete.mjs +11 -3
  2. package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-combobox.mjs +11 -3
  4. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
  5. package/fesm2022/radix-ng-primitives-core.mjs +9 -6
  6. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-date-field.mjs +18 -8
  8. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  9. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +9 -0
  10. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -1
  11. package/fesm2022/radix-ng-primitives-focus-scope.mjs +241 -95
  12. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  13. package/fesm2022/radix-ng-primitives-menu.mjs +97 -9
  14. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  15. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +17 -3
  16. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  17. package/fesm2022/radix-ng-primitives-popper.mjs +148 -23
  18. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  19. package/fesm2022/radix-ng-primitives-portal.mjs +16 -5
  20. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  21. package/fesm2022/radix-ng-primitives-select.mjs +14 -6
  22. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-time-field.mjs +12 -4
  24. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  25. package/package.json +1 -5
  26. package/types/radix-ng-primitives-core.d.ts +15 -12
  27. package/types/radix-ng-primitives-date-field.d.ts +14 -4
  28. package/types/radix-ng-primitives-floating-focus-manager.d.ts +7 -0
  29. package/types/radix-ng-primitives-focus-scope.d.ts +61 -44
  30. package/types/radix-ng-primitives-menu.d.ts +14 -3
  31. package/types/radix-ng-primitives-popper.d.ts +136 -43
  32. package/types/radix-ng-primitives-portal.d.ts +18 -8
  33. package/types/radix-ng-primitives-time-field.d.ts +12 -4
  34. package/fesm2022/radix-ng-primitives-focus-guards.mjs +0 -53
  35. package/fesm2022/radix-ng-primitives-focus-guards.mjs.map +0 -1
  36. package/focus-guards/README.md +0 -1
  37. package/types/radix-ng-primitives-focus-guards.d.ts +0 -15
@@ -2,19 +2,31 @@ import * as i0 from '@angular/core';
2
2
  import { effect, InjectionToken, signal, inject, Injector, DestroyRef, ElementRef, input, booleanAttribute, computed, output, afterNextRender, Directive } from '@angular/core';
3
3
  import { getActiveElement, createContext } from '@radix-ng/primitives/core';
4
4
 
5
- const AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
6
- const AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
7
- const EVENT_OPTIONS = { bubbles: false, cancelable: true };
5
+ const CANDIDATE_SELECTOR = 'a[href],button,input,select,textarea,summary,details,iframe,object,embed,[tabindex],[contenteditable]:not([contenteditable="false"]),audio[controls],video[controls]';
6
+ const getNodeName = (node) => node.nodeName.toLowerCase();
7
+ const isNode = (value) => value != null && typeof value.nodeType === 'number';
8
8
  /**
9
- * The real target of a (possibly retargeted) event, piercing shadow boundaries via `composedPath()`.
10
- * Falls back to `event.target` when `composedPath` is unavailable.
9
+ * Owner-window-safe `HTMLElement` check. A raw `value instanceof HTMLElement` is realm-sensitive it
10
+ * returns `false` for an element from another document (iframe / popup window), whose realm has its own
11
+ * `HTMLElement` constructor. Resolve the constructor from the node's own `defaultView` (the same pattern
12
+ * as `dismissable-layer`'s `dismiss.ts`; Base UI `isHTMLElement`).
11
13
  */
12
- function getEventTarget(event) {
13
- return event.composedPath?.()[0] ?? event.target;
14
- }
14
+ const isHTMLElement = (value) => {
15
+ if (!isNode(value)) {
16
+ return false;
17
+ }
18
+ const view = value.ownerDocument?.defaultView;
19
+ return view ? value instanceof view.HTMLElement : value instanceof HTMLElement;
20
+ };
21
+ /** A shadow root, detected structurally (`DOCUMENT_FRAGMENT_NODE` with a `host`) so it is realm- and SSR-safe. */
22
+ const isShadowRoot = (node) => node !== null && node.nodeType === 11 && 'host' in node;
23
+ const getComputedStyleOf = (element) => {
24
+ const view = element.ownerDocument.defaultView;
25
+ return view ? view.getComputedStyle(element) : null;
26
+ };
15
27
  /**
16
28
  * Shadow-DOM-aware containment: whether `node` is `container` or lives inside it, crossing shadow roots
17
- * via their `host` (unlike `Node.contains`, which stops at a shadow boundary).
29
+ * via their `host` (unlike `Node.contains`, which stops at a shadow boundary). Base UI `contains`.
18
30
  */
19
31
  function composedContains(container, node) {
20
32
  let current = node;
@@ -22,97 +34,190 @@ function composedContains(container, node) {
22
34
  if (current === container) {
23
35
  return true;
24
36
  }
25
- current = current instanceof ShadowRoot ? current.host : current.parentNode;
37
+ current = isShadowRoot(current) ? current.host : current.parentNode;
26
38
  }
27
39
  return false;
28
40
  }
29
- /**
30
- * Attempts focusing the first element in a list of candidates.
31
- * Stops when focus has actually moved.
32
- */
33
- function focusFirst(candidates, { select = false } = {}) {
34
- const previouslyFocusedElement = getActiveElement();
35
- for (const candidate of candidates) {
36
- focus(candidate, { select });
37
- if (getActiveElement() !== previouslyFocusedElement)
38
- return true;
41
+ function isHiddenByStyles(styles) {
42
+ return styles.visibility === 'hidden' || styles.visibility === 'collapse';
43
+ }
44
+ function isElementVisible(element, styles) {
45
+ if (!element.isConnected || !styles || isHiddenByStyles(styles)) {
46
+ return false;
39
47
  }
40
- return;
48
+ if (typeof element.checkVisibility === 'function') {
49
+ return element.checkVisibility();
50
+ }
51
+ return styles.display !== 'none' && styles.display !== 'contents';
41
52
  }
42
- /**
43
- * Returns a list of potential tabbable candidates.
44
- *
45
- * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
46
- * elements are not visible. This cannot be worked out easily by just reading a property, but rather
47
- * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
48
- *
49
- * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
50
- * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
51
- */
52
- function getTabbableCandidates(container) {
53
- const nodes = [];
54
- const walker = container.ownerDocument.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
55
- acceptNode: (node) => {
56
- const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
57
- if (node.disabled || node.hidden || isHiddenInput)
58
- return NodeFilter.FILTER_SKIP;
59
- // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
60
- // runtime's understanding of tabbability, so this automatically accounts
61
- // for any kind of element that could be tabbed to.
62
- return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
53
+ /** The composed parent: an assigned `<slot>`, the element's parent, or the shadow host at a boundary. */
54
+ function getParentElement(element) {
55
+ const assignedSlot = element.assignedSlot;
56
+ if (assignedSlot) {
57
+ return assignedSlot;
58
+ }
59
+ if (element.parentElement) {
60
+ return element.parentElement;
61
+ }
62
+ const rootNode = element.getRootNode();
63
+ return isShadowRoot(rootNode) ? rootNode.host : null;
64
+ }
65
+ function getDetailsSummary(details) {
66
+ for (const child of Array.from(details.children)) {
67
+ if (getNodeName(child) === 'summary') {
68
+ return child;
63
69
  }
64
- });
65
- while (walker.nextNode())
66
- nodes.push(walker.currentNode);
67
- // we do not take into account the order of nodes with positive `tabIndex` as it
68
- // hinders accessibility to have tab order different from visual order.
69
- return nodes;
70
- }
71
- function isHidden(node, { upTo }) {
72
- const view = node.ownerDocument.defaultView;
73
- if (!view) {
74
- return false; // no view (detached / SSR) — cannot resolve computed styles, treat as visible
75
70
  }
76
- if (view.getComputedStyle(node).visibility === 'hidden')
77
- return true;
78
- while (node) {
79
- // we stop at `upTo` (excluding it)
80
- if (upTo !== undefined && node === upTo)
71
+ return null;
72
+ }
73
+ function isWithinOpenDetailsSummary(element, details) {
74
+ const summary = getDetailsSummary(details);
75
+ return !!summary && (element === summary || composedContains(summary, element));
76
+ }
77
+ function isFocusableCandidate(element) {
78
+ const nodeName = element ? getNodeName(element) : '';
79
+ return (element != null &&
80
+ element.matches(CANDIDATE_SELECTOR) &&
81
+ // a `<summary>` is only focusable as the (first) summary of a `<details>`
82
+ (nodeName !== 'summary' ||
83
+ (element.parentElement != null &&
84
+ getNodeName(element.parentElement) === 'details' &&
85
+ getDetailsSummary(element.parentElement) === element)) &&
86
+ // a `<details>` with its own summary is not focusable (the summary is)
87
+ (nodeName !== 'details' || getDetailsSummary(element) == null) &&
88
+ (nodeName !== 'input' || element.type !== 'hidden'));
89
+ }
90
+ function isVisibleInTabbableTree(element, isAncestor) {
91
+ const styles = getComputedStyleOf(element);
92
+ if (!isAncestor) {
93
+ return isElementVisible(element, styles);
94
+ }
95
+ return !!styles && styles.display !== 'none';
96
+ }
97
+ function isFocusableElement(element) {
98
+ if (!isFocusableCandidate(element) || !element.isConnected || element.matches(':disabled')) {
99
+ return false;
100
+ }
101
+ for (let current = element; current; current = getParentElement(current)) {
102
+ const isAncestor = current !== element;
103
+ const isSlot = getNodeName(current) === 'slot';
104
+ if (current.hasAttribute('inert')) {
81
105
  return false;
82
- if (view.getComputedStyle(node).display === 'none')
83
- return true;
84
- node = node.parentElement;
106
+ }
107
+ if ((isAncestor &&
108
+ getNodeName(current) === 'details' &&
109
+ !current.open &&
110
+ !isWithinOpenDetailsSummary(element, current)) ||
111
+ current.hasAttribute('hidden') ||
112
+ (!isSlot && !isVisibleInTabbableTree(current, isAncestor))) {
113
+ return false;
114
+ }
85
115
  }
86
- return false;
116
+ return true;
87
117
  }
88
- /**
89
- * Returns the first visible element in a list.
90
- * NOTE: Only checks visibility up to the `container`.
91
- */
92
- function findVisible(elements, container) {
93
- for (const element of elements) {
94
- // we stop checking if it's hidden at the `container` level (excluding)
95
- if (!isHidden(element, { upTo: container }))
96
- return element;
118
+ /** The effective tab index, giving `<details>`/media/`contenteditable` their implicit `0`. */
119
+ function getTabIndex(element) {
120
+ const tabIndex = element.tabIndex;
121
+ if (tabIndex < 0) {
122
+ const nodeName = getNodeName(element);
123
+ if (nodeName === 'details' ||
124
+ nodeName === 'audio' ||
125
+ nodeName === 'video' ||
126
+ (isHTMLElement(element) && element.isContentEditable)) {
127
+ return 0;
128
+ }
129
+ }
130
+ return tabIndex;
131
+ }
132
+ function getNamedRadioInput(element) {
133
+ if (getNodeName(element) !== 'input') {
134
+ return null;
97
135
  }
98
- return undefined;
136
+ const input = element;
137
+ return input.type === 'radio' && input.name !== '' ? input : null;
138
+ }
139
+ /** Within a named radio group only the checked radio (or the first, if none is checked) is tabbable. */
140
+ function isTabbableRadio(element, candidates) {
141
+ const input = getNamedRadioInput(element);
142
+ if (!input) {
143
+ return true;
144
+ }
145
+ const checkedRadio = candidates.find((candidate) => {
146
+ const radio = getNamedRadioInput(candidate);
147
+ return radio?.name === input.name && radio.form === input.form && radio.checked;
148
+ });
149
+ if (checkedRadio) {
150
+ return checkedRadio === input;
151
+ }
152
+ return (candidates.find((candidate) => {
153
+ const radio = getNamedRadioInput(candidate);
154
+ return radio?.name === input.name && radio.form === input.form;
155
+ }) === input);
156
+ }
157
+ /** The composed children of a node: `<slot>` assigned elements, then shadow-root children, else children. */
158
+ function getComposedChildren(container) {
159
+ if (isHTMLElement(container) && getNodeName(container) === 'slot') {
160
+ const assignedElements = container.assignedElements({ flatten: true });
161
+ if (assignedElements.length > 0) {
162
+ return assignedElements;
163
+ }
164
+ }
165
+ if (isHTMLElement(container) && container.shadowRoot) {
166
+ return Array.from(container.shadowRoot.children);
167
+ }
168
+ return Array.from(container.children);
169
+ }
170
+ function appendCandidates(container, list) {
171
+ getComposedChildren(container).forEach((child) => {
172
+ if (isFocusableCandidate(child)) {
173
+ list.push(child);
174
+ }
175
+ appendCandidates(child, list);
176
+ });
177
+ }
178
+ /** Collects elements matching `selector` across the composed tree (shadow / slot aware). */
179
+ function queryComposedAll(container, selector) {
180
+ const list = [];
181
+ const walk = (node) => {
182
+ getComposedChildren(node).forEach((child) => {
183
+ if (isHTMLElement(child) && child.matches(selector)) {
184
+ list.push(child);
185
+ }
186
+ walk(child);
187
+ });
188
+ };
189
+ walk(container);
190
+ return list;
191
+ }
192
+ /** Whether `element` is reachable by Tab right now (Base UI `isTabbable`). */
193
+ function isTabbable(element) {
194
+ return isFocusableElement(element) && getTabIndex(element) >= 0;
195
+ }
196
+ /** All programmatically focusable elements inside `container`, in composed document order. */
197
+ function focusable(container) {
198
+ const candidates = [];
199
+ appendCandidates(container, candidates);
200
+ return candidates.filter(isFocusableElement);
201
+ }
202
+ /** All keyboard-tabbable elements inside `container`, in composed document order (Base UI `tabbable`). */
203
+ function tabbable(container) {
204
+ const candidates = focusable(container);
205
+ return candidates.filter((element) => getTabIndex(element) >= 0 && isTabbableRadio(element, candidates));
99
206
  }
100
207
  /**
101
- * Returns the first and last tabbable elements inside a container.
208
+ * Back-compat alias for {@link tabbable} historically returned a looser `TreeWalker` approximation;
209
+ * now the full Base UI tabbable set. Kept so existing imports (`getTabbableCandidates`) keep working.
102
210
  */
103
- function getTabbableEdges(container) {
104
- const candidates = getTabbableCandidates(container);
105
- const first = findVisible(candidates, container);
106
- const last = findVisible(candidates.reverse(), container);
107
- return [first, last];
211
+ function getTabbableCandidates(container) {
212
+ return tabbable(container);
108
213
  }
109
- /** Visible tabbable elements of `root` in document order (the basis for tab-order navigation). */
110
- function visibleTabbablesIn(root) {
111
- return getTabbableCandidates(root).filter((el) => !isHidden(el, { upTo: root }));
214
+ /** The first and last tabbable elements inside `container`. */
215
+ function getTabbableEdges(container) {
216
+ const list = tabbable(container);
217
+ return [list[0], list[list.length - 1]];
112
218
  }
113
- /** The tabbable one step (`dir`) from the document's active element, within `container`. */
114
219
  function getTabbableIn(container, dir) {
115
- const list = visibleTabbablesIn(container);
220
+ const list = tabbable(container);
116
221
  if (list.length === 0) {
117
222
  return undefined;
118
223
  }
@@ -134,12 +239,11 @@ function getPreviousTabbable(reference) {
134
239
  const body = (reference?.ownerDocument ?? document).body;
135
240
  return getTabbableIn(body, -1) ?? reference;
136
241
  }
137
- /** The tabbable `dir` steps from `reference` in the document, wrapping around. */
138
242
  function getTabbableNearElement(reference, dir) {
139
243
  if (!reference) {
140
244
  return null;
141
245
  }
142
- const list = visibleTabbablesIn(reference.ownerDocument.body);
246
+ const list = tabbable(reference.ownerDocument.body);
143
247
  const index = list.indexOf(reference);
144
248
  if (list.length === 0 || index === -1) {
145
249
  return null;
@@ -154,13 +258,45 @@ function getTabbableAfterElement(reference) {
154
258
  function getTabbableBeforeElement(reference) {
155
259
  return getTabbableNearElement(reference, -1);
156
260
  }
261
+
262
+ const AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
263
+ const AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
264
+ const EVENT_OPTIONS = { bubbles: false, cancelable: true };
265
+ /**
266
+ * The real target of a (possibly retargeted) event, piercing shadow boundaries via `composedPath()`.
267
+ * Falls back to `event.target` when `composedPath` is unavailable.
268
+ */
269
+ function getEventTarget(event) {
270
+ return event.composedPath?.()[0] ?? event.target;
271
+ }
272
+ /**
273
+ * Attempts focusing the first element in a list of candidates.
274
+ * Stops when focus has actually moved.
275
+ *
276
+ * Reads the active element from `root` (a focus scope passes its host's `ownerDocument`); falling back to
277
+ * the global `document` would, in an iframe / multi-document scope, never detect that focus moved inside
278
+ * the inner document and so walk past every candidate, leaving focus on the last one instead of the first.
279
+ */
280
+ function focusFirst(candidates, { select = false, root } = {}) {
281
+ const ownerRoot = root ?? candidates[0]?.ownerDocument ?? document;
282
+ const previouslyFocusedElement = getActiveElement(ownerRoot);
283
+ for (const candidate of candidates) {
284
+ focus(candidate, { select });
285
+ if (getActiveElement(ownerRoot) !== previouslyFocusedElement)
286
+ return true;
287
+ }
288
+ return;
289
+ }
157
290
  function isSelectableInput(element) {
158
291
  return element instanceof HTMLInputElement && 'select' in element;
159
292
  }
160
293
  function focus(element, { select = false } = {}) {
161
294
  // only focus if that element is focusable
162
295
  if (element && element.focus) {
163
- const previouslyFocusedElement = getActiveElement();
296
+ // Read the active element from the element's own document so the same-element select() check stays
297
+ // correct across iframes / multi-document scopes (consistent with this module's ownerDocument focus).
298
+ const root = 'ownerDocument' in element ? element.ownerDocument : undefined;
299
+ const previouslyFocusedElement = getActiveElement(root ?? document);
164
300
  // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users
165
301
  element.focus({ preventScroll: true });
166
302
  // only select if its not the same element, it supports selection and we need to select
@@ -218,14 +354,17 @@ function createAriaOwnsAnchor(ownerDocument, portalId) {
218
354
  * trigger steps onto the guard instead of jumping into the content.
219
355
  */
220
356
  function disableFocusInside(container) {
221
- for (const element of getTabbableCandidates(container)) {
357
+ for (const element of tabbable(container)) {
222
358
  element.setAttribute(SAVED_TABINDEX_ATTR, element.getAttribute('tabindex') ?? '');
223
359
  element.setAttribute('tabindex', '-1');
224
360
  }
225
361
  }
226
- /** Restores the tabbability that {@link disableFocusInside} suspended. Base UI `enableFocusInside`. */
362
+ /**
363
+ * Restores the tabbability that {@link disableFocusInside} suspended. Base UI `enableFocusInside`.
364
+ * Collects markers across the composed tree so guards inside shadow roots / slots are restored too.
365
+ */
227
366
  function enableFocusInside(container) {
228
- container.querySelectorAll(`[${SAVED_TABINDEX_ATTR}]`).forEach((element) => {
367
+ queryComposedAll(container, `[${SAVED_TABINDEX_ATTR}]`).forEach((element) => {
229
368
  const original = element.getAttribute(SAVED_TABINDEX_ATTR);
230
369
  element.removeAttribute(SAVED_TABINDEX_ATTR);
231
370
  if (original) {
@@ -350,9 +489,6 @@ function arrayRemove(array, item) {
350
489
  }
351
490
  return copy;
352
491
  }
353
- function removeLinks(items) {
354
- return items.filter((el) => el.tagName !== 'A');
355
- }
356
492
 
357
493
  const [injectFocusScopeContext, provideFocusScopeContext] = createContext('FocusScope Context', 'utils/focus-scope');
358
494
  const rootContext = () => {
@@ -493,8 +629,9 @@ class RdxFocusScope {
493
629
  container.addEventListener(AUTOFOCUS_ON_MOUNT, mountEventHandler);
494
630
  container.dispatchEvent(mountEvent);
495
631
  if (!mountEvent.defaultPrevented) {
496
- focusFirst(removeLinks(getTabbableCandidates(container)), {
497
- select: true
632
+ focusFirst(getTabbableCandidates(container), {
633
+ select: true,
634
+ root: this.ownerDocument
498
635
  });
499
636
  if (getActiveElement(this.ownerDocument) === previouslyFocusedElement)
500
637
  focus(container);
@@ -546,6 +683,15 @@ class RdxFocusScope {
546
683
  return (!!active && active !== this.ownerDocument.body && !composedContains(this.elementRef.nativeElement, active));
547
684
  }
548
685
  handleKeyDown(event) {
686
+ // Only a looping or trapped scope polices Tab at its edges. A plain non-modal scope must let Tab
687
+ // through so the browser can reach whatever follows the host — e.g. the hidden outer focus guards
688
+ // `RdxFloatingFocusManager` places around it (calling `preventDefault()` here would fire first and
689
+ // strand focus at the boundary, defeating the guard). A paused scope (a nested scope took over)
690
+ // also stands down so it can't double-handle a bubbled Tab. Mirrors Base UI / Radix `FocusScope`:
691
+ // `if ((!loop && !trapped) || focusScope.paused) return`.
692
+ if ((!this.loop() && !this.isTrapped()) || this.focusScope.paused()) {
693
+ return;
694
+ }
549
695
  const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
550
696
  const focusedElement = getActiveElement(this.ownerDocument);
551
697
  if (isTabKey && focusedElement) {
@@ -592,5 +738,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
592
738
  * Generated bundle index. Do not edit.
593
739
  */
594
740
 
595
- export { AUTOFOCUS_ON_MOUNT, AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS, FOCUS_GUARD_ATTR, FOCUS_GUARD_STYLE, RdxFocusScope, RdxFocusScopeConfigToken, composedContains, createAriaOwnsAnchor, createFocusGuard, disableFocusInside, enableFocusInside, findVisible, focus, focusFirst, getEventTarget, getNextTabbable, getPreviousTabbable, getTabbableAfterElement, getTabbableBeforeElement, getTabbableCandidates, getTabbableEdges, injectFocusScopeContext, isHidden, isOutsideEvent, isSelectableInput, provideFocusScopeContext, provideRdxFocusScopeConfig, useFocusGuardsTabbability };
741
+ export { AUTOFOCUS_ON_MOUNT, AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS, FOCUS_GUARD_ATTR, FOCUS_GUARD_STYLE, RdxFocusScope, RdxFocusScopeConfigToken, composedContains, createAriaOwnsAnchor, createFocusGuard, disableFocusInside, enableFocusInside, focus, focusFirst, focusable, getEventTarget, getNextTabbable, getPreviousTabbable, getTabbableAfterElement, getTabbableBeforeElement, getTabbableCandidates, getTabbableEdges, injectFocusScopeContext, isOutsideEvent, isSelectableInput, isTabbable, provideFocusScopeContext, provideRdxFocusScopeConfig, queryComposedAll, tabbable, useFocusGuardsTabbability };
596
742
  //# sourceMappingURL=radix-ng-primitives-focus-scope.mjs.map