@zag-js/tabbable
Advanced tools
Comparing version 0.0.0-dev-20230328140202 to 0.0.0-dev-20230504114722
@@ -1,42 +0,4 @@ | ||
type IncludeContainerType = boolean | "if-empty"; | ||
declare const focusableSelector: string; | ||
/** | ||
* Returns the focusable elements within the element | ||
*/ | ||
declare const getFocusables: (container: Pick<HTMLElement, "querySelectorAll"> | null, includeContainer?: IncludeContainerType) => HTMLElement[]; | ||
/** | ||
* Whether this element is focusable | ||
*/ | ||
declare function isFocusable(element: HTMLElement | null): element is HTMLElement; | ||
declare function getFirstFocusable(container: HTMLElement, includeContainer?: IncludeContainerType): HTMLElement; | ||
/** | ||
* Returns the tabbable elements within the element | ||
*/ | ||
declare function getTabbables(container: HTMLElement | null, includeContainer?: IncludeContainerType): HTMLElement[]; | ||
/** | ||
* Whether this element is tabbable | ||
*/ | ||
declare function isTabbable(el: HTMLElement | null): el is HTMLElement; | ||
/** | ||
* Returns the first focusable element within the element | ||
*/ | ||
declare function getFirstTabbable(container: HTMLElement | null, includeContainer?: IncludeContainerType): HTMLElement; | ||
/** | ||
* Returns the last focusable element within the element | ||
*/ | ||
declare function getLastTabbable(container: HTMLElement | null, includeContainer?: IncludeContainerType): HTMLElement; | ||
/** | ||
* Returns the first and last focusable elements within the element | ||
*/ | ||
declare function getTabbableEdges(container: HTMLElement | null, includeContainer?: IncludeContainerType): HTMLElement[]; | ||
/** | ||
* Returns the next tabbable element after the current element | ||
*/ | ||
declare function getNextTabbable(container: HTMLElement | null, current?: HTMLElement | null): HTMLElement | null; | ||
/** | ||
* Proxies tab focus within a container to a reference element | ||
* when the container is rendered in a portal | ||
*/ | ||
declare function proxyTabFocus(container: HTMLElement | null, reference: HTMLElement | null, cb: (elementToFocus: HTMLElement) => void): () => void; | ||
export { focusableSelector, getFirstFocusable, getFirstTabbable, getFocusables, getLastTabbable, getNextTabbable, getTabbableEdges, getTabbables, isFocusable, isTabbable, proxyTabFocus }; | ||
export { proxyTabFocus } from './proxy-tab-focus.js'; | ||
export { getFirstFocusable, getFocusables, isFocusable } from './focusable.js'; | ||
export { getFirstTabbable, getLastTabbable, getNextTabbable, getTabbableEdges, getTabbables, isTabbable } from './tabbable.js'; | ||
import './shared.js'; |
@@ -23,3 +23,2 @@ "use strict"; | ||
__export(src_exports, { | ||
focusableSelector: () => focusableSelector, | ||
getFirstFocusable: () => getFirstFocusable, | ||
@@ -37,2 +36,7 @@ getFirstTabbable: () => getFirstTabbable, | ||
module.exports = __toCommonJS(src_exports); | ||
// src/proxy-tab-focus.ts | ||
var import_dom_query = require("@zag-js/dom-query"); | ||
// src/shared.ts | ||
var isHTMLElement = (element) => typeof element === "object" && element !== null && element.nodeType === 1; | ||
@@ -50,2 +54,4 @@ var isFrame = (element) => isHTMLElement(element) && element.tagName === "IFRAME"; | ||
var focusableSelector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], iframe, object, embed, area[href], audio[controls], video[controls], [contenteditable]:not([contenteditable='false']), details > summary:first-of-type"; | ||
// src/focusable.ts | ||
var getFocusables = (container, includeContainer = false) => { | ||
@@ -69,3 +75,3 @@ if (!container) | ||
function isFocusable(element) { | ||
if (!element) | ||
if (!element || element.closest("[inert]")) | ||
return false; | ||
@@ -78,2 +84,4 @@ return element.matches(focusableSelector) && isVisible(element); | ||
} | ||
// src/tabbable.ts | ||
function getTabbables(container, includeContainer) { | ||
@@ -100,2 +108,4 @@ if (!container) | ||
function isTabbable(el) { | ||
if (el != null && el.tabIndex > 0) | ||
return true; | ||
return isFocusable(el) && !hasNegativeTabIndex(el); | ||
@@ -126,3 +136,6 @@ } | ||
} | ||
function proxyTabFocus(container, reference, cb) { | ||
// src/proxy-tab-focus.ts | ||
function proxyTabFocusImpl(container, options = {}) { | ||
const { triggerElement, onFocus } = options; | ||
const doc = container?.ownerDocument || document; | ||
@@ -137,7 +150,7 @@ const body = doc.body; | ||
if (event.shiftKey && (doc.activeElement === firstTabbable || noTabbableElements)) { | ||
elementToFocus = reference; | ||
} else if (!event.shiftKey && doc.activeElement === reference) { | ||
elementToFocus = triggerElement; | ||
} else if (!event.shiftKey && doc.activeElement === triggerElement) { | ||
elementToFocus = firstTabbable; | ||
} else if (!event.shiftKey && (doc.activeElement === lastTabbable || noTabbableElements)) { | ||
elementToFocus = getNextTabbable(body, reference); | ||
elementToFocus = getNextTabbable(body, triggerElement); | ||
} | ||
@@ -147,3 +160,3 @@ if (!elementToFocus) | ||
event.preventDefault(); | ||
cb(elementToFocus); | ||
onFocus?.(elementToFocus) ?? elementToFocus.focus(); | ||
} | ||
@@ -155,5 +168,19 @@ doc?.addEventListener("keydown", onKeyDown, true); | ||
} | ||
function proxyTabFocus(container, options) { | ||
const { defer, triggerElement, ...restOptions } = options; | ||
const func = defer ? import_dom_query.raf : (v) => v(); | ||
const cleanups = []; | ||
cleanups.push( | ||
func(() => { | ||
const node = typeof container === "function" ? container() : container; | ||
const trigger = typeof triggerElement === "function" ? triggerElement() : triggerElement; | ||
cleanups.push(proxyTabFocusImpl(node, { triggerElement: trigger, ...restOptions })); | ||
}) | ||
); | ||
return () => { | ||
cleanups.forEach((fn) => fn?.()); | ||
}; | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
focusableSelector, | ||
getFirstFocusable, | ||
@@ -160,0 +187,0 @@ getFirstTabbable, |
{ | ||
"name": "@zag-js/tabbable", | ||
"version": "0.0.0-dev-20230328140202", | ||
"version": "0.0.0-dev-20230504114722", | ||
"description": "Small utility that returns an array of all* tabbable DOM nodes within a containing node.", | ||
@@ -29,2 +29,5 @@ "keywords": [ | ||
}, | ||
"dependencies": { | ||
"@zag-js/dom-query": "0.1.4" | ||
}, | ||
"module": "dist/index.mjs", | ||
@@ -31,0 +34,0 @@ "types": "dist/index.d.ts", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
34524
22
852
1
1
+ Added@zag-js/dom-query@0.1.4
+ Added@zag-js/dom-query@0.1.4(transitive)