UNPKG

@chakra-ui/descendant

Version:

Register child nodes of a react element for better accessibility

245 lines (240 loc) 8.71 kB
'use client' "use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // src/index.ts var src_exports = {}; __export(src_exports, { createDescendantContext: () => createDescendantContext, default: () => createDescendantContext }); module.exports = __toCommonJS(src_exports); // src/use-descendant.ts var import_react_context = require("@chakra-ui/react-context"); var import_react_use_merge_refs = require("@chakra-ui/react-use-merge-refs"); var import_react2 = require("react"); // src/utils.ts var import_react = require("react"); function sortNodes(nodes) { return nodes.sort((a, b) => { const compare = a.compareDocumentPosition(b); if (compare & Node.DOCUMENT_POSITION_FOLLOWING || compare & Node.DOCUMENT_POSITION_CONTAINED_BY) { return -1; } if (compare & Node.DOCUMENT_POSITION_PRECEDING || compare & Node.DOCUMENT_POSITION_CONTAINS) { return 1; } if (compare & Node.DOCUMENT_POSITION_DISCONNECTED || compare & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) { throw Error("Cannot sort the given nodes."); } else { return 0; } }); } var isElement = (el) => typeof el == "object" && "nodeType" in el && el.nodeType === Node.ELEMENT_NODE; function getNextIndex(current, max, loop) { let next = current + 1; if (loop && next >= max) next = 0; return next; } function getPrevIndex(current, max, loop) { let next = current - 1; if (loop && next < 0) next = max; return next; } var useSafeLayoutEffect = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect; var cast = (value) => value; // src/descendant.ts var DescendantsManager = class { constructor() { __publicField(this, "descendants", /* @__PURE__ */ new Map()); __publicField(this, "register", (nodeOrOptions) => { if (nodeOrOptions == null) return; if (isElement(nodeOrOptions)) { return this.registerNode(nodeOrOptions); } return (node) => { this.registerNode(node, nodeOrOptions); }; }); __publicField(this, "unregister", (node) => { this.descendants.delete(node); const sorted = sortNodes(Array.from(this.descendants.keys())); this.assignIndex(sorted); }); __publicField(this, "destroy", () => { this.descendants.clear(); }); __publicField(this, "assignIndex", (descendants) => { this.descendants.forEach((descendant) => { const index = descendants.indexOf(descendant.node); descendant.index = index; descendant.node.dataset["index"] = descendant.index.toString(); }); }); __publicField(this, "count", () => this.descendants.size); __publicField(this, "enabledCount", () => this.enabledValues().length); __publicField(this, "values", () => { const values = Array.from(this.descendants.values()); return values.sort((a, b) => a.index - b.index); }); __publicField(this, "enabledValues", () => { return this.values().filter((descendant) => !descendant.disabled); }); __publicField(this, "item", (index) => { if (this.count() === 0) return void 0; return this.values()[index]; }); __publicField(this, "enabledItem", (index) => { if (this.enabledCount() === 0) return void 0; return this.enabledValues()[index]; }); __publicField(this, "first", () => this.item(0)); __publicField(this, "firstEnabled", () => this.enabledItem(0)); __publicField(this, "last", () => this.item(this.descendants.size - 1)); __publicField(this, "lastEnabled", () => { const lastIndex = this.enabledValues().length - 1; return this.enabledItem(lastIndex); }); __publicField(this, "indexOf", (node) => { var _a, _b; if (!node) return -1; return (_b = (_a = this.descendants.get(node)) == null ? void 0 : _a.index) != null ? _b : -1; }); __publicField(this, "enabledIndexOf", (node) => { if (node == null) return -1; return this.enabledValues().findIndex((i) => i.node.isSameNode(node)); }); __publicField(this, "next", (index, loop = true) => { const next = getNextIndex(index, this.count(), loop); return this.item(next); }); __publicField(this, "nextEnabled", (index, loop = true) => { const item = this.item(index); if (!item) return; const enabledIndex = this.enabledIndexOf(item.node); const nextEnabledIndex = getNextIndex( enabledIndex, this.enabledCount(), loop ); return this.enabledItem(nextEnabledIndex); }); __publicField(this, "prev", (index, loop = true) => { const prev = getPrevIndex(index, this.count() - 1, loop); return this.item(prev); }); __publicField(this, "prevEnabled", (index, loop = true) => { const item = this.item(index); if (!item) return; const enabledIndex = this.enabledIndexOf(item.node); const prevEnabledIndex = getPrevIndex( enabledIndex, this.enabledCount() - 1, loop ); return this.enabledItem(prevEnabledIndex); }); __publicField(this, "registerNode", (node, options) => { if (!node || this.descendants.has(node)) return; const keys = Array.from(this.descendants.keys()).concat(node); const sorted = sortNodes(keys); if (options == null ? void 0 : options.disabled) { options.disabled = !!options.disabled; } const descendant = { node, index: -1, ...options }; this.descendants.set(node, descendant); this.assignIndex(sorted); }); } }; // src/use-descendant.ts function useDescendants() { const descendants = (0, import_react2.useRef)(new DescendantsManager()); useSafeLayoutEffect(() => { return () => descendants.current.destroy(); }); return descendants.current; } var [DescendantsContextProvider, useDescendantsContext] = (0, import_react_context.createContext)({ name: "DescendantsProvider", errorMessage: "useDescendantsContext must be used within DescendantsProvider" }); function useDescendant(options) { const descendants = useDescendantsContext(); const [index, setIndex] = (0, import_react2.useState)(-1); const ref = (0, import_react2.useRef)(null); useSafeLayoutEffect(() => { return () => { if (!ref.current) return; descendants.unregister(ref.current); }; }, []); useSafeLayoutEffect(() => { if (!ref.current) return; const dataIndex = Number(ref.current.dataset["index"]); if (index != dataIndex && !Number.isNaN(dataIndex)) { setIndex(dataIndex); } }); const refCallback = options ? cast(descendants.register(options)) : cast(descendants.register); return { descendants, index, enabledIndex: descendants.enabledIndexOf(ref.current), register: (0, import_react_use_merge_refs.mergeRefs)(refCallback, ref) }; } function createDescendantContext() { const ContextProvider = cast(DescendantsContextProvider); const _useDescendantsContext = () => cast(useDescendantsContext()); const _useDescendant = (options) => useDescendant(options); const _useDescendants = () => useDescendants(); return [ // context provider ContextProvider, // call this when you need to read from context _useDescendantsContext, // descendants state information, to be called and passed to `ContextProvider` _useDescendants, // descendant index information _useDescendant ]; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createDescendantContext }); //# sourceMappingURL=index.js.map