@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
1 lines • 12.9 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","names":["enabledValue","createContext","mergeRefs"],"sources":["../../../../src/hooks/use-descendants/index.ts"],"sourcesContent":["\"use client\"\n\nimport type { RefCallback } from \"react\"\nimport { useRef } from \"react\"\nimport {\n createContext,\n isNumber,\n isTruthyDataAttr,\n mergeRefs,\n runIfFn,\n useSafeLayoutEffect,\n} from \"../../utils\"\n\nconst sortNodes = (nodes: Node[]) =>\n nodes.sort((a, b) => {\n const compare = a.compareDocumentPosition(b)\n\n if (\n compare & Node.DOCUMENT_POSITION_FOLLOWING ||\n compare & Node.DOCUMENT_POSITION_CONTAINED_BY\n )\n return -1\n\n if (\n compare & Node.DOCUMENT_POSITION_PRECEDING ||\n compare & Node.DOCUMENT_POSITION_CONTAINS\n )\n return 1\n\n if (\n compare & Node.DOCUMENT_POSITION_DISCONNECTED ||\n compare & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC\n ) {\n console.warn(\"Cannot sort the given nodes.\")\n return 0\n } else {\n return 0\n }\n })\n\nconst getNextIndex = (current: number, max: number, loop: boolean) => {\n let next = current + 1\n\n if (loop && next >= max) next = 0\n\n return next\n}\n\nconst getPrevIndex = (current: number, max: number, loop: boolean) => {\n let next = current - 1\n\n if (loop && next < 0) next = max\n\n return next\n}\n\nexport type DescendantProps<Y extends HTMLElement = HTMLElement, M = {}> = M & {\n disabled?: ((node: Y) => boolean) | boolean\n}\n\nexport type Descendant<\n Y extends HTMLElement = HTMLElement,\n M = {},\n> = DescendantProps<Y, M> & {\n index: number\n node: Y\n recurred?: boolean\n}\n\nconst descendantManager = <Y extends HTMLElement = HTMLElement, M = {}>() => {\n const descendants = new Map<Y, Descendant<Y, M>>()\n\n const setIndexes = (next: Node[]) => {\n descendants.forEach((descendant) => {\n const index = next.indexOf(descendant.node)\n\n descendant.index = index\n descendant.node.dataset.index = descendant.index.toString()\n })\n }\n\n const set = (node: null | Y, props?: DescendantProps<Y, M>) => {\n if (!node || descendants.has(node)) return\n\n const keys = Array.from(descendants.keys()).concat(node)\n const sorted = sortNodes(keys)\n\n const descendant = { ...props, index: -1, node } as Descendant<Y, M>\n\n descendants.set(node, descendant)\n\n setIndexes(sorted)\n }\n\n const destroy = () => descendants.clear()\n\n const register = (props?: DescendantProps<Y, M>): RefCallback<Y> => {\n return (node: null | Y) => set(node, props)\n }\n\n const unregister = (node?: null | Y) => {\n if (node == null) return\n\n descendants.delete(node)\n\n const sorted = sortNodes(Array.from(descendants.keys()))\n\n setIndexes(sorted)\n }\n\n const count = () => values().length\n\n const enabledCount = () => enabledValues().length\n\n const active = (\n target?: Descendant<Y, M> | null | Y,\n options?: FocusOptions,\n ) => {\n if (!target) return\n\n if (!(target instanceof Node)) target = target.node\n\n if (isTruthyDataAttr(target.dataset.activedescendant)) return\n\n const descendants = values()\n\n descendants.forEach(({ node }) => {\n delete node.dataset.activedescendant\n })\n\n target.dataset.activedescendant = \"\"\n\n if (options) target.focus(options)\n }\n\n const indexOf = (target?: Descendant<Y, M> | null | Y) => {\n if (!target) return -1\n\n if (target instanceof Node) {\n return descendants.get(target)?.index ?? -1\n } else {\n return descendants.get(target.node)?.index ?? -1\n }\n }\n\n const enabledIndexOf = (target?: Descendant<Y, M> | null | Y) => {\n if (!target) return -1\n\n if (target instanceof Node) {\n return enabledValues().findIndex(({ node }) => node.isSameNode(target))\n } else {\n return enabledValues().findIndex(({ node }) =>\n node.isSameNode(target.node),\n )\n }\n }\n\n const values = () =>\n Array.from(descendants.values()).sort((a, b) => a.index - b.index)\n\n const enabledValues = () =>\n values().filter(({ disabled, node }) => !runIfFn(disabled, node))\n\n const value = (indexOrNode: null | number | Y) => {\n if (!count() || indexOrNode == null) return undefined\n\n return isNumber(indexOrNode)\n ? values()[indexOrNode]\n : descendants.get(indexOrNode)\n }\n\n const enabledValue = (index: number) => {\n if (!enabledCount()) return undefined\n\n return enabledValues()[index]\n }\n\n const firstValue = () => value(0)\n\n const enabledFirstValue = () => enabledValue(0)\n\n const lastValue = () => value(count() - 1)\n\n const enabledLastValue = () => enabledValue(enabledCount() - 1)\n\n const prevValue = (\n indexOrNode: Descendant<Y, M> | null | number | Y,\n loop = true,\n ) => {\n if (!count()) return undefined\n\n const currentIndex = isNumber(indexOrNode)\n ? indexOrNode\n : indexOf(indexOrNode)\n\n if (currentIndex === -1) return undefined\n\n const prevIndex = getPrevIndex(currentIndex, count() - 1, loop)\n\n return value(prevIndex)\n }\n\n const enabledPrevValue = (\n indexOrNode: Descendant<Y, M> | null | number | Y,\n loop = true,\n ) => {\n if (!enabledCount()) return undefined\n\n let index = isNumber(indexOrNode) ? indexOrNode : indexOf(indexOrNode)\n let enabledValue = null\n let recurred = false\n\n while (enabledValue == null) {\n index--\n\n if (index < 0) {\n if (!loop) return\n\n index = count() - 1\n recurred = true\n }\n\n const descendant = value(index)\n\n enabledValue =\n descendant && !runIfFn(descendant.disabled, descendant.node)\n ? descendant\n : null\n }\n\n if (recurred) enabledValue.recurred = recurred\n\n return enabledValue\n }\n\n const nextValue = (\n indexOrNode: Descendant<Y, M> | null | number | Y,\n loop = true,\n ) => {\n if (!count()) return undefined\n\n const currentIndex = isNumber(indexOrNode)\n ? indexOrNode\n : indexOf(indexOrNode)\n\n if (currentIndex === -1) return undefined\n\n const nextIndex = getNextIndex(currentIndex, count(), loop)\n\n return value(nextIndex)\n }\n\n const enabledNextValue = (\n indexOrNode: Descendant<Y, M> | null | number | Y,\n loop = true,\n ) => {\n if (!enabledCount()) return undefined\n\n let index = isNumber(indexOrNode) ? indexOrNode : indexOf(indexOrNode)\n let enabledValue = null\n let recurred = false\n\n while (enabledValue == null) {\n index++\n\n if (index >= count()) {\n if (!loop) return\n\n index = 0\n recurred = true\n }\n\n const descendant = value(index)\n\n enabledValue =\n descendant && !runIfFn(descendant.disabled, descendant.node)\n ? descendant\n : null\n }\n\n if (recurred) enabledValue.recurred = recurred\n\n return enabledValue\n }\n\n return {\n active,\n count,\n destroy,\n enabledCount,\n enabledFirstValue,\n enabledIndexOf,\n enabledLastValue,\n enabledNextValue,\n enabledPrevValue,\n enabledValue,\n enabledValues,\n firstValue,\n indexOf,\n lastValue,\n nextValue,\n prevValue,\n register,\n unregister,\n value,\n values,\n }\n}\n\nexport type Descendants<Y extends HTMLElement, M = {}> = ReturnType<\n typeof descendantManager<Y, M>\n>\n\nexport type CreateDescendantRegister<Y extends HTMLElement, M = {}> = (\n props?: DescendantProps<Y, M>,\n) => RefCallback<Y>\n\n/**\n * `useDescendants` is a custom hook that manages descendants.\n *\n * @see https://yamada-ui.com/docs/hooks/use-descendants\n */\nexport const createDescendants = <\n Y extends HTMLElement = HTMLElement,\n M = {},\n>() => {\n const [DescendantsContext, useDescendantsContext] = createContext<\n Descendants<Y, M>\n >({\n name: \"DescendantsContext\",\n })\n\n const useDescendantRegister = (descendants?: Descendants<Y, M>) => {\n const ref = useRef<Y>(null)\n\n useSafeLayoutEffect(() => {\n return () => {\n if (ref.current) descendants?.unregister(ref.current)\n }\n }, [])\n\n return (props?: DescendantProps<Y, M>): RefCallback<Y> =>\n mergeRefs(ref, descendants?.register(props))\n }\n\n const useDescendants = () => {\n const descendants = useRef(descendantManager<Y, M>())\n\n useSafeLayoutEffect(() => {\n return () => descendants.current.destroy()\n })\n\n return descendants.current\n }\n\n const useDescendant = (props?: DescendantProps<Y, M>) => {\n const descendants = useDescendantsContext()\n const createRegister = useDescendantRegister(descendants)\n\n return {\n descendants,\n register: createRegister(props),\n }\n }\n\n return {\n DescendantsContext,\n useDescendant,\n useDescendantRegister,\n useDescendants,\n useDescendantsContext,\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,aAAa,UACjB,MAAM,MAAM,GAAG,MAAM;CACnB,MAAM,UAAU,EAAE,wBAAwB,EAAE;AAE5C,KACE,UAAU,KAAK,+BACf,UAAU,KAAK,+BAEf,QAAO;AAET,KACE,UAAU,KAAK,+BACf,UAAU,KAAK,2BAEf,QAAO;AAET,KACE,UAAU,KAAK,kCACf,UAAU,KAAK,2CACf;AACA,UAAQ,KAAK,+BAA+B;AAC5C,SAAO;OAEP,QAAO;EAET;AAEJ,MAAM,gBAAgB,SAAiB,KAAa,SAAkB;CACpE,IAAI,OAAO,UAAU;AAErB,KAAI,QAAQ,QAAQ,IAAK,QAAO;AAEhC,QAAO;;AAGT,MAAM,gBAAgB,SAAiB,KAAa,SAAkB;CACpE,IAAI,OAAO,UAAU;AAErB,KAAI,QAAQ,OAAO,EAAG,QAAO;AAE7B,QAAO;;AAgBT,MAAM,0BAAuE;CAC3E,MAAM,8BAAc,IAAI,KAA0B;CAElD,MAAM,cAAc,SAAiB;AACnC,cAAY,SAAS,eAAe;AAGlC,cAAW,QAFG,KAAK,QAAQ,WAAW,KAAK;AAG3C,cAAW,KAAK,QAAQ,QAAQ,WAAW,MAAM,UAAU;IAC3D;;CAGJ,MAAM,OAAO,MAAgB,UAAkC;AAC7D,MAAI,CAAC,QAAQ,YAAY,IAAI,KAAK,CAAE;EAGpC,MAAM,SAAS,UADF,MAAM,KAAK,YAAY,MAAM,CAAC,CAAC,OAAO,KAAK,CAC1B;EAE9B,MAAM,aAAa;GAAE,GAAG;GAAO,OAAO;GAAI;GAAM;AAEhD,cAAY,IAAI,MAAM,WAAW;AAEjC,aAAW,OAAO;;CAGpB,MAAM,gBAAgB,YAAY,OAAO;CAEzC,MAAM,YAAY,UAAkD;AAClE,UAAQ,SAAmB,IAAI,MAAM,MAAM;;CAG7C,MAAM,cAAc,SAAoB;AACtC,MAAI,QAAQ,KAAM;AAElB,cAAY,OAAO,KAAK;AAIxB,aAFe,UAAU,MAAM,KAAK,YAAY,MAAM,CAAC,CAAC,CAEtC;;CAGpB,MAAM,cAAc,QAAQ,CAAC;CAE7B,MAAM,qBAAqB,eAAe,CAAC;CAE3C,MAAM,UACJ,QACA,YACG;AACH,MAAI,CAAC,OAAQ;AAEb,MAAI,EAAE,kBAAkB,MAAO,UAAS,OAAO;AAE/C,8DAAqB,OAAO,QAAQ,iBAAiB,CAAE;AAIvD,EAFoB,QAAQ,CAEhB,SAAS,EAAE,WAAW;AAChC,UAAO,KAAK,QAAQ;IACpB;AAEF,SAAO,QAAQ,mBAAmB;AAElC,MAAI,QAAS,QAAO,MAAM,QAAQ;;CAGpC,MAAM,WAAW,WAAyC;AACxD,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,kBAAkB,KACpB,QAAO,YAAY,IAAI,OAAO,EAAE,SAAS;MAEzC,QAAO,YAAY,IAAI,OAAO,KAAK,EAAE,SAAS;;CAIlD,MAAM,kBAAkB,WAAyC;AAC/D,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,kBAAkB,KACpB,QAAO,eAAe,CAAC,WAAW,EAAE,WAAW,KAAK,WAAW,OAAO,CAAC;MAEvE,QAAO,eAAe,CAAC,WAAW,EAAE,WAClC,KAAK,WAAW,OAAO,KAAK,CAC7B;;CAIL,MAAM,eACJ,MAAM,KAAK,YAAY,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;CAEpE,MAAM,sBACJ,QAAQ,CAAC,QAAQ,EAAE,UAAU,WAAW,gDAAS,UAAU,KAAK,CAAC;CAEnE,MAAM,SAAS,gBAAmC;AAChD,MAAI,CAAC,OAAO,IAAI,eAAe,KAAM,QAAO;AAE5C,yDAAgB,YAAY,GACxB,QAAQ,CAAC,eACT,YAAY,IAAI,YAAY;;CAGlC,MAAM,gBAAgB,UAAkB;AACtC,MAAI,CAAC,cAAc,CAAE,QAAO;AAE5B,SAAO,eAAe,CAAC;;CAGzB,MAAM,mBAAmB,MAAM,EAAE;CAEjC,MAAM,0BAA0B,aAAa,EAAE;CAE/C,MAAM,kBAAkB,MAAM,OAAO,GAAG,EAAE;CAE1C,MAAM,yBAAyB,aAAa,cAAc,GAAG,EAAE;CAE/D,MAAM,aACJ,aACA,OAAO,SACJ;AACH,MAAI,CAAC,OAAO,CAAE,QAAO;EAErB,MAAM,+DAAwB,YAAY,GACtC,cACA,QAAQ,YAAY;AAExB,MAAI,iBAAiB,GAAI,QAAO;AAIhC,SAAO,MAFW,aAAa,cAAc,OAAO,GAAG,GAAG,KAAK,CAExC;;CAGzB,MAAM,oBACJ,aACA,OAAO,SACJ;AACH,MAAI,CAAC,cAAc,CAAE,QAAO;EAE5B,IAAI,wDAAiB,YAAY,GAAG,cAAc,QAAQ,YAAY;EACtE,IAAIA,iBAAe;EACnB,IAAI,WAAW;AAEf,SAAOA,kBAAgB,MAAM;AAC3B;AAEA,OAAI,QAAQ,GAAG;AACb,QAAI,CAAC,KAAM;AAEX,YAAQ,OAAO,GAAG;AAClB,eAAW;;GAGb,MAAM,aAAa,MAAM,MAAM;AAE/B,oBACE,cAAc,gDAAS,WAAW,UAAU,WAAW,KAAK,GACxD,aACA;;AAGR,MAAI,SAAU,gBAAa,WAAW;AAEtC,SAAOA;;CAGT,MAAM,aACJ,aACA,OAAO,SACJ;AACH,MAAI,CAAC,OAAO,CAAE,QAAO;EAErB,MAAM,+DAAwB,YAAY,GACtC,cACA,QAAQ,YAAY;AAExB,MAAI,iBAAiB,GAAI,QAAO;AAIhC,SAAO,MAFW,aAAa,cAAc,OAAO,EAAE,KAAK,CAEpC;;CAGzB,MAAM,oBACJ,aACA,OAAO,SACJ;AACH,MAAI,CAAC,cAAc,CAAE,QAAO;EAE5B,IAAI,wDAAiB,YAAY,GAAG,cAAc,QAAQ,YAAY;EACtE,IAAIA,iBAAe;EACnB,IAAI,WAAW;AAEf,SAAOA,kBAAgB,MAAM;AAC3B;AAEA,OAAI,SAAS,OAAO,EAAE;AACpB,QAAI,CAAC,KAAM;AAEX,YAAQ;AACR,eAAW;;GAGb,MAAM,aAAa,MAAM,MAAM;AAE/B,oBACE,cAAc,gDAAS,WAAW,UAAU,WAAW,KAAK,GACxD,aACA;;AAGR,MAAI,SAAU,gBAAa,WAAW;AAEtC,SAAOA;;AAGT,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;;;AAgBH,MAAa,0BAGN;CACL,MAAM,CAAC,oBAAoB,yBAAyBC,8BAElD,EACA,MAAM,sBACP,CAAC;CAEF,MAAM,yBAAyB,gBAAoC;EACjE,MAAM,wBAAgB,KAAK;AAE3B,2CAA0B;AACxB,gBAAa;AACX,QAAI,IAAI,QAAS,cAAa,WAAW,IAAI,QAAQ;;KAEtD,EAAE,CAAC;AAEN,UAAQ,UACNC,sBAAU,KAAK,aAAa,SAAS,MAAM,CAAC;;CAGhD,MAAM,uBAAuB;EAC3B,MAAM,gCAAqB,mBAAyB,CAAC;AAErD,2CAA0B;AACxB,gBAAa,YAAY,QAAQ,SAAS;IAC1C;AAEF,SAAO,YAAY;;CAGrB,MAAM,iBAAiB,UAAkC;EACvD,MAAM,cAAc,uBAAuB;AAG3C,SAAO;GACL;GACA,UAJqB,sBAAsB,YAAY,CAI9B,MAAM;GAChC;;AAGH,QAAO;EACL;EACA;EACA;EACA;EACA;EACD"}