ng-primitives 0.120.3 → 0.120.4
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.
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { inject, Injector, NgZone, signal, afterNextRender, input, booleanAttribute, Directive } from '@angular/core';
|
|
3
3
|
import { FocusMonitor, InteractivityChecker } from '@angular/cdk/a11y';
|
|
4
4
|
import { injectElementRef } from 'ng-primitives/internal';
|
|
5
|
-
import { NgpOverlay } from 'ng-primitives/portal';
|
|
5
|
+
import { NgpOverlay, NgpOverlayRegistry } from 'ng-primitives/portal';
|
|
6
6
|
import { createPrimitive, attrBinding, dataBinding, onDestroy, listener } from 'ng-primitives/state';
|
|
7
7
|
import { safeTakeUntilDestroyed } from 'ng-primitives/utils';
|
|
8
8
|
|
|
@@ -77,6 +77,7 @@ const [NgpFocusTrapStateToken, ngpFocusTrap, injectFocusTrapState, provideFocusT
|
|
|
77
77
|
const focusMonitor = inject(FocusMonitor);
|
|
78
78
|
const interactivityChecker = inject(InteractivityChecker);
|
|
79
79
|
const ngZone = inject(NgZone);
|
|
80
|
+
const overlayRegistry = inject(NgpOverlayRegistry);
|
|
80
81
|
// Create a new focus trap
|
|
81
82
|
const focusTrap = new FocusTrap();
|
|
82
83
|
// Store the mutation observer
|
|
@@ -154,18 +155,28 @@ const [NgpFocusTrapStateToken, ngpFocusTrap, injectFocusTrapState, provideFocusT
|
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
157
|
/**
|
|
157
|
-
* Whether the given element belongs to another focus trap
|
|
158
|
+
* Whether the given element belongs to another focus trap, a CDK overlay
|
|
159
|
+
* container, or an open ng-primitives overlay (e.g. a combobox/menu/popover
|
|
160
|
+
* dropdown rendered into a portal).
|
|
158
161
|
*
|
|
159
|
-
* When focus moves to these elements we must not redirect it back, because
|
|
160
|
-
* manage their own focus
|
|
161
|
-
*
|
|
162
|
-
* yank focus back into the dialog
|
|
162
|
+
* When focus moves to these elements we must not redirect it back, because
|
|
163
|
+
* they manage their own focus or are an intentional escape hatch from the
|
|
164
|
+
* trapped region. Without this check, opening a combobox dropdown from
|
|
165
|
+
* inside a focus-trapped dialog would yank focus back into the dialog as
|
|
166
|
+
* soon as the user tried to focus the dropdown's search input, making it
|
|
167
|
+
* unusable.
|
|
163
168
|
*
|
|
164
|
-
* See https://github.com/
|
|
165
|
-
* and https://github.com/
|
|
169
|
+
* See https://github.com/ng-primitives/ng-primitives/issues/682
|
|
170
|
+
* and https://github.com/ng-primitives/ng-primitives/issues/687
|
|
166
171
|
*/
|
|
167
172
|
function isAllowedExternalTarget(target) {
|
|
168
|
-
|
|
173
|
+
if (!target) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (target.closest?.('[data-focus-trap]') || target.closest?.('.cdk-overlay-container')) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
return overlayRegistry.findContainingOverlay(target) !== null;
|
|
169
180
|
}
|
|
170
181
|
/**
|
|
171
182
|
* If the focused element gets removed from the DOM, browsers move focus back to the document.body.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-primitives-focus-trap.mjs","sources":["../../../../packages/ng-primitives/focus-trap/src/focus-trap/focus-trap-state.ts","../../../../packages/ng-primitives/focus-trap/src/focus-trap/focus-trap.ts","../../../../packages/ng-primitives/focus-trap/src/ng-primitives-focus-trap.ts"],"sourcesContent":["import { FocusMonitor, FocusOrigin, InteractivityChecker } from '@angular/cdk/a11y';\nimport { afterNextRender, inject, Injector, NgZone, signal, Signal } from '@angular/core';\nimport { injectElementRef } from 'ng-primitives/internal';\nimport { NgpOverlay } from 'ng-primitives/portal';\nimport {\n attrBinding,\n createPrimitive,\n dataBinding,\n listener,\n onDestroy,\n} from 'ng-primitives/state';\nimport { safeTakeUntilDestroyed } from 'ng-primitives/utils';\n\nclass FocusTrap {\n /**\n * Whether the focus trap is active.\n */\n active: boolean = false;\n\n /**\n * Activates the focus trap.\n */\n activate(): void {\n this.active = true;\n }\n\n /**\n * Deactivates the focus trap.\n */\n deactivate(): void {\n this.active = false;\n }\n}\n\nclass FocusTrapStack {\n /**\n * The stack of focus traps.\n */\n private readonly stack: FocusTrap[] = [];\n\n /**\n * Adds a focus trap to the stack.\n */\n add(focusTrap: FocusTrap): void {\n // deactivate the previous focus trap\n this.stack.forEach(t => t.deactivate());\n\n // add the new focus trap and activate it\n this.stack.push(focusTrap);\n focusTrap.activate();\n }\n\n /**\n * Removes a focus trap from the stack.\n */\n remove(focusTrap: FocusTrap): void {\n // remove the focus trap\n const index = this.stack.indexOf(focusTrap);\n\n if (index < 0) {\n return;\n }\n\n // Only reactivate the previous trap if we're removing from the top of the stack.\n // This prevents reactivating a parent trap when closing all overlays (where the\n // parent is removed first, leaving the child at the top).\n const wasOnTop = index === this.stack.length - 1;\n\n // Deactivate the removed focus trap so its event listeners don't interfere\n focusTrap.deactivate();\n this.stack.splice(index, 1);\n\n // activate the previous focus trap only if removed from top\n if (wasOnTop) {\n const previous = this.stack[this.stack.length - 1];\n\n if (previous) {\n previous.activate();\n }\n }\n }\n}\n\n// create a global stack of focus traps\nconst focusTrapStack = new FocusTrapStack();\n\n/**\n * The state for the FocusTrap primitive.\n */\nexport interface NgpFocusTrapState {\n // No public API\n}\n\n/**\n * The props for the FocusTrap primitive.\n */\nexport interface NgpFocusTrapProps {\n /**\n * Whether the focus trap is disabled.\n */\n readonly disabled?: Signal<boolean>;\n\n /**\n * The focus origin to use when programmatically focusing elements.\n * If not provided, falls back to the FocusMonitor's last known origin.\n */\n readonly focusOrigin?: Signal<FocusOrigin>;\n}\n\nexport const [NgpFocusTrapStateToken, ngpFocusTrap, injectFocusTrapState, provideFocusTrapState] =\n createPrimitive(\n 'NgpFocusTrap',\n ({ disabled = signal(false), focusOrigin }: NgpFocusTrapProps) => {\n const element = injectElementRef();\n const overlay = inject(NgpOverlay, { optional: true });\n const injector = inject(Injector);\n const focusMonitor = inject(FocusMonitor);\n const interactivityChecker = inject(InteractivityChecker);\n const ngZone = inject(NgZone);\n\n // Create a new focus trap\n const focusTrap = new FocusTrap();\n\n // Store the mutation observer\n let mutationObserver: MutationObserver | null = null;\n\n // Store the last focused element\n let lastFocusedElement: HTMLElement | null = null;\n\n // Host bindings\n attrBinding(element, 'tabindex', '-1');\n dataBinding(element, 'data-focus-trap', () => (disabled() ? null : ''));\n\n // Setup the focus trap\n function setupFocusTrap(): void {\n focusTrapStack.add(focusTrap);\n\n mutationObserver = new MutationObserver(handleMutations);\n\n // Setup event listeners\n ngZone.runOutsideAngular(() => {\n mutationObserver!.observe(element.nativeElement, {\n childList: true,\n subtree: true,\n });\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n });\n\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = element.nativeElement.contains(previouslyFocusedElement);\n\n // Only perform initial focusing if the focus trap is not disabled\n if (!hasFocusedCandidate && !disabled?.()) {\n // we do this to ensure the content is rendered before we try to find the first focusable element\n // and focus it\n afterNextRender(\n {\n write: () => {\n focusFirst();\n\n // if the focus didn't change, focus the container\n if (document.activeElement === previouslyFocusedElement) {\n focus(element.nativeElement);\n }\n },\n },\n { injector },\n );\n }\n }\n\n function teardownFocusTrap(): void {\n // Remove from stack (this also deactivates the trap)\n focusTrapStack.remove(focusTrap);\n mutationObserver?.disconnect();\n mutationObserver = null;\n\n // Remove event listeners\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n }\n\n function handleFocusIn(event: FocusEvent): void {\n if (!focusTrap.active || disabled?.()) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (element.nativeElement.contains(target)) {\n lastFocusedElement = target;\n } else if (isAllowedExternalTarget(target)) {\n // Don't interfere — see `isAllowedExternalTarget` for details.\n } else {\n focus(lastFocusedElement);\n }\n }\n\n /**\n * Handles the `focusout` event.\n */\n function handleFocusOut(event: FocusEvent) {\n if (!focusTrap.active || disabled?.() || event.relatedTarget === null) {\n return;\n }\n\n const relatedTarget = event.relatedTarget as HTMLElement;\n\n if (\n !element.nativeElement.contains(relatedTarget) &&\n !isAllowedExternalTarget(relatedTarget)\n ) {\n focus(lastFocusedElement);\n }\n }\n\n /**\n * Whether the given element belongs to another focus trap or a CDK overlay container.\n *\n * When focus moves to these elements we must not redirect it back, because they\n * manage their own focus trapping. Without this check, opening a CDK overlay\n * (e.g. a select dropdown) from inside a focus-trapped dialog would immediately\n * yank focus back into the dialog, making the overlay unusable.\n *\n * See https://github.com/nicecod3r/ng-primitives/issues/682\n * and https://github.com/nicecod3r/ng-primitives/issues/687\n */\n function isAllowedExternalTarget(target: HTMLElement | null): boolean {\n return !!(\n target?.closest?.('[data-focus-trap]') || target?.closest?.('.cdk-overlay-container')\n );\n }\n\n /**\n * If the focused element gets removed from the DOM, browsers move focus back to the document.body.\n * We move focus to the container to keep focus trapped correctly.\n */\n function handleMutations(mutations: MutationRecord[]): void {\n // Don't handle mutations if the focus trap is not active (e.g., during overlay close)\n if (!focusTrap.active || disabled?.()) {\n return;\n }\n\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (focusedElement !== document.body) {\n return;\n }\n\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) {\n focus(element.nativeElement);\n }\n }\n }\n\n /**\n * Handles the `keydown` event.\n */\n function handleKeyDown(event: KeyboardEvent): void {\n if (!focusTrap.active || disabled?.()) {\n return;\n }\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) {\n event.preventDefault();\n }\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n focus(first);\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n focus(last);\n }\n }\n }\n }\n\n /**\n * Returns the first and last tabbable elements inside a container.\n */\n function getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates);\n const last = findVisible(candidates.reverse());\n return [first, last] as const;\n }\n\n /**\n * Returns a list of potential focusable elements inside a container.\n */\n function getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: HTMLElement) =>\n interactivityChecker.isTabbable(node)\n ? NodeFilter.FILTER_ACCEPT\n : NodeFilter.FILTER_SKIP,\n });\n while (walker.nextNode()) {\n nodes.push(walker.currentNode as HTMLElement);\n }\n return nodes;\n }\n\n /**\n * Returns the first visible element in a list.\n */\n function findVisible(elements: HTMLElement[]) {\n return elements.find(element => interactivityChecker.isVisible(element)) ?? null;\n }\n\n function focus(element: HTMLElement | null): void {\n if (!element) {\n return;\n }\n // Use the provided focus origin if available, otherwise fall back to FocusMonitor's last origin\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const origin = focusOrigin?.() ?? (focusMonitor as any)._lastFocusOrigin ?? 'program';\n focusMonitor.focusVia(element, origin, {\n preventScroll: true,\n });\n }\n\n function focusFirst(): void {\n const previouslyFocusedElement = document.activeElement;\n\n for (const candidate of getTabbableCandidates(element.nativeElement)) {\n focus(candidate);\n\n if (document.activeElement !== previouslyFocusedElement) {\n return;\n }\n }\n }\n\n // Setup the focus trap\n setupFocusTrap();\n\n // Teardown the focus trap on destroy\n onDestroy(teardownFocusTrap);\n\n // Listen to keydown events\n listener(element, 'keydown', handleKeyDown);\n\n // if this is used within an overlay we must remove the focus trap from the stack as soon as the overlay is closing\n // this prevents reactivation of parent focus traps during component destruction\n overlay?.closing.pipe(safeTakeUntilDestroyed()).subscribe(() => {\n focusTrapStack.remove(focusTrap);\n });\n\n return {} satisfies NgpFocusTrapState;\n },\n );\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { booleanAttribute, Directive, input } from '@angular/core';\nimport { ngpFocusTrap, provideFocusTrapState } from './focus-trap-state';\n\n/**\n * This implementation is based on the Radix UI FocusScope:\n * https://github.com/radix-ui/primitives/blob/main/packages/react/focus-scope/src/FocusScope.tsx#L306\n */\n\n/**\n * The `NgpFocusTrap` directive traps focus within the host element.\n */\n@Directive({\n selector: '[ngpFocusTrap]',\n exportAs: 'ngpFocusTrap',\n providers: [provideFocusTrapState()],\n})\nexport class NgpFocusTrap {\n /**\n * Whether the focus trap is disabled.\n */\n readonly disabled = input<boolean, BooleanInput>(false, {\n alias: 'ngpFocusTrapDisabled',\n transform: booleanAttribute,\n });\n\n /**\n * The focus trap state.\n */\n constructor() {\n ngpFocusTrap({ disabled: this.disabled });\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-primitives-focus-trap.mjs","sources":["../../../../packages/ng-primitives/focus-trap/src/focus-trap/focus-trap-state.ts","../../../../packages/ng-primitives/focus-trap/src/focus-trap/focus-trap.ts","../../../../packages/ng-primitives/focus-trap/src/ng-primitives-focus-trap.ts"],"sourcesContent":["import { FocusMonitor, FocusOrigin, InteractivityChecker } from '@angular/cdk/a11y';\nimport { afterNextRender, inject, Injector, NgZone, signal, Signal } from '@angular/core';\nimport { injectElementRef } from 'ng-primitives/internal';\nimport { NgpOverlay, NgpOverlayRegistry } from 'ng-primitives/portal';\nimport {\n attrBinding,\n createPrimitive,\n dataBinding,\n listener,\n onDestroy,\n} from 'ng-primitives/state';\nimport { safeTakeUntilDestroyed } from 'ng-primitives/utils';\n\nclass FocusTrap {\n /**\n * Whether the focus trap is active.\n */\n active: boolean = false;\n\n /**\n * Activates the focus trap.\n */\n activate(): void {\n this.active = true;\n }\n\n /**\n * Deactivates the focus trap.\n */\n deactivate(): void {\n this.active = false;\n }\n}\n\nclass FocusTrapStack {\n /**\n * The stack of focus traps.\n */\n private readonly stack: FocusTrap[] = [];\n\n /**\n * Adds a focus trap to the stack.\n */\n add(focusTrap: FocusTrap): void {\n // deactivate the previous focus trap\n this.stack.forEach(t => t.deactivate());\n\n // add the new focus trap and activate it\n this.stack.push(focusTrap);\n focusTrap.activate();\n }\n\n /**\n * Removes a focus trap from the stack.\n */\n remove(focusTrap: FocusTrap): void {\n // remove the focus trap\n const index = this.stack.indexOf(focusTrap);\n\n if (index < 0) {\n return;\n }\n\n // Only reactivate the previous trap if we're removing from the top of the stack.\n // This prevents reactivating a parent trap when closing all overlays (where the\n // parent is removed first, leaving the child at the top).\n const wasOnTop = index === this.stack.length - 1;\n\n // Deactivate the removed focus trap so its event listeners don't interfere\n focusTrap.deactivate();\n this.stack.splice(index, 1);\n\n // activate the previous focus trap only if removed from top\n if (wasOnTop) {\n const previous = this.stack[this.stack.length - 1];\n\n if (previous) {\n previous.activate();\n }\n }\n }\n}\n\n// create a global stack of focus traps\nconst focusTrapStack = new FocusTrapStack();\n\n/**\n * The state for the FocusTrap primitive.\n */\nexport interface NgpFocusTrapState {\n // No public API\n}\n\n/**\n * The props for the FocusTrap primitive.\n */\nexport interface NgpFocusTrapProps {\n /**\n * Whether the focus trap is disabled.\n */\n readonly disabled?: Signal<boolean>;\n\n /**\n * The focus origin to use when programmatically focusing elements.\n * If not provided, falls back to the FocusMonitor's last known origin.\n */\n readonly focusOrigin?: Signal<FocusOrigin>;\n}\n\nexport const [NgpFocusTrapStateToken, ngpFocusTrap, injectFocusTrapState, provideFocusTrapState] =\n createPrimitive(\n 'NgpFocusTrap',\n ({ disabled = signal(false), focusOrigin }: NgpFocusTrapProps) => {\n const element = injectElementRef();\n const overlay = inject(NgpOverlay, { optional: true });\n const injector = inject(Injector);\n const focusMonitor = inject(FocusMonitor);\n const interactivityChecker = inject(InteractivityChecker);\n const ngZone = inject(NgZone);\n const overlayRegistry = inject(NgpOverlayRegistry);\n\n // Create a new focus trap\n const focusTrap = new FocusTrap();\n\n // Store the mutation observer\n let mutationObserver: MutationObserver | null = null;\n\n // Store the last focused element\n let lastFocusedElement: HTMLElement | null = null;\n\n // Host bindings\n attrBinding(element, 'tabindex', '-1');\n dataBinding(element, 'data-focus-trap', () => (disabled() ? null : ''));\n\n // Setup the focus trap\n function setupFocusTrap(): void {\n focusTrapStack.add(focusTrap);\n\n mutationObserver = new MutationObserver(handleMutations);\n\n // Setup event listeners\n ngZone.runOutsideAngular(() => {\n mutationObserver!.observe(element.nativeElement, {\n childList: true,\n subtree: true,\n });\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n });\n\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = element.nativeElement.contains(previouslyFocusedElement);\n\n // Only perform initial focusing if the focus trap is not disabled\n if (!hasFocusedCandidate && !disabled?.()) {\n // we do this to ensure the content is rendered before we try to find the first focusable element\n // and focus it\n afterNextRender(\n {\n write: () => {\n focusFirst();\n\n // if the focus didn't change, focus the container\n if (document.activeElement === previouslyFocusedElement) {\n focus(element.nativeElement);\n }\n },\n },\n { injector },\n );\n }\n }\n\n function teardownFocusTrap(): void {\n // Remove from stack (this also deactivates the trap)\n focusTrapStack.remove(focusTrap);\n mutationObserver?.disconnect();\n mutationObserver = null;\n\n // Remove event listeners\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n }\n\n function handleFocusIn(event: FocusEvent): void {\n if (!focusTrap.active || disabled?.()) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (element.nativeElement.contains(target)) {\n lastFocusedElement = target;\n } else if (isAllowedExternalTarget(target)) {\n // Don't interfere — see `isAllowedExternalTarget` for details.\n } else {\n focus(lastFocusedElement);\n }\n }\n\n /**\n * Handles the `focusout` event.\n */\n function handleFocusOut(event: FocusEvent) {\n if (!focusTrap.active || disabled?.() || event.relatedTarget === null) {\n return;\n }\n\n const relatedTarget = event.relatedTarget as HTMLElement;\n\n if (\n !element.nativeElement.contains(relatedTarget) &&\n !isAllowedExternalTarget(relatedTarget)\n ) {\n focus(lastFocusedElement);\n }\n }\n\n /**\n * Whether the given element belongs to another focus trap, a CDK overlay\n * container, or an open ng-primitives overlay (e.g. a combobox/menu/popover\n * dropdown rendered into a portal).\n *\n * When focus moves to these elements we must not redirect it back, because\n * they manage their own focus or are an intentional escape hatch from the\n * trapped region. Without this check, opening a combobox dropdown from\n * inside a focus-trapped dialog would yank focus back into the dialog as\n * soon as the user tried to focus the dropdown's search input, making it\n * unusable.\n *\n * See https://github.com/ng-primitives/ng-primitives/issues/682\n * and https://github.com/ng-primitives/ng-primitives/issues/687\n */\n function isAllowedExternalTarget(target: HTMLElement | null): boolean {\n if (!target) {\n return false;\n }\n if (target.closest?.('[data-focus-trap]') || target.closest?.('.cdk-overlay-container')) {\n return true;\n }\n return overlayRegistry.findContainingOverlay(target) !== null;\n }\n\n /**\n * If the focused element gets removed from the DOM, browsers move focus back to the document.body.\n * We move focus to the container to keep focus trapped correctly.\n */\n function handleMutations(mutations: MutationRecord[]): void {\n // Don't handle mutations if the focus trap is not active (e.g., during overlay close)\n if (!focusTrap.active || disabled?.()) {\n return;\n }\n\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (focusedElement !== document.body) {\n return;\n }\n\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) {\n focus(element.nativeElement);\n }\n }\n }\n\n /**\n * Handles the `keydown` event.\n */\n function handleKeyDown(event: KeyboardEvent): void {\n if (!focusTrap.active || disabled?.()) {\n return;\n }\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) {\n event.preventDefault();\n }\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n focus(first);\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n focus(last);\n }\n }\n }\n }\n\n /**\n * Returns the first and last tabbable elements inside a container.\n */\n function getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates);\n const last = findVisible(candidates.reverse());\n return [first, last] as const;\n }\n\n /**\n * Returns a list of potential focusable elements inside a container.\n */\n function getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: HTMLElement) =>\n interactivityChecker.isTabbable(node)\n ? NodeFilter.FILTER_ACCEPT\n : NodeFilter.FILTER_SKIP,\n });\n while (walker.nextNode()) {\n nodes.push(walker.currentNode as HTMLElement);\n }\n return nodes;\n }\n\n /**\n * Returns the first visible element in a list.\n */\n function findVisible(elements: HTMLElement[]) {\n return elements.find(element => interactivityChecker.isVisible(element)) ?? null;\n }\n\n function focus(element: HTMLElement | null): void {\n if (!element) {\n return;\n }\n // Use the provided focus origin if available, otherwise fall back to FocusMonitor's last origin\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const origin = focusOrigin?.() ?? (focusMonitor as any)._lastFocusOrigin ?? 'program';\n focusMonitor.focusVia(element, origin, {\n preventScroll: true,\n });\n }\n\n function focusFirst(): void {\n const previouslyFocusedElement = document.activeElement;\n\n for (const candidate of getTabbableCandidates(element.nativeElement)) {\n focus(candidate);\n\n if (document.activeElement !== previouslyFocusedElement) {\n return;\n }\n }\n }\n\n // Setup the focus trap\n setupFocusTrap();\n\n // Teardown the focus trap on destroy\n onDestroy(teardownFocusTrap);\n\n // Listen to keydown events\n listener(element, 'keydown', handleKeyDown);\n\n // if this is used within an overlay we must remove the focus trap from the stack as soon as the overlay is closing\n // this prevents reactivation of parent focus traps during component destruction\n overlay?.closing.pipe(safeTakeUntilDestroyed()).subscribe(() => {\n focusTrapStack.remove(focusTrap);\n });\n\n return {} satisfies NgpFocusTrapState;\n },\n );\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { booleanAttribute, Directive, input } from '@angular/core';\nimport { ngpFocusTrap, provideFocusTrapState } from './focus-trap-state';\n\n/**\n * This implementation is based on the Radix UI FocusScope:\n * https://github.com/radix-ui/primitives/blob/main/packages/react/focus-scope/src/FocusScope.tsx#L306\n */\n\n/**\n * The `NgpFocusTrap` directive traps focus within the host element.\n */\n@Directive({\n selector: '[ngpFocusTrap]',\n exportAs: 'ngpFocusTrap',\n providers: [provideFocusTrapState()],\n})\nexport class NgpFocusTrap {\n /**\n * Whether the focus trap is disabled.\n */\n readonly disabled = input<boolean, BooleanInput>(false, {\n alias: 'ngpFocusTrapDisabled',\n transform: booleanAttribute,\n });\n\n /**\n * The focus trap state.\n */\n constructor() {\n ngpFocusTrap({ disabled: this.disabled });\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ng-primitives",
|
|
3
3
|
"description": "Angular Primitives is a low-level headless UI component library with a focus on accessibility, customization, and developer experience. ",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.120.
|
|
5
|
+
"version": "0.120.4",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"angular",
|
|
8
8
|
"primitives",
|