@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
1 lines • 10.6 kB
Source Map (JSON)
{"version":3,"file":"use-tabs.cjs","names":["createDescendants","createContext","useControllableState","getRootProps: PropGetter","mergeRefs","getListProps: PropGetter"],"sources":["../../../../src/components/tabs/use-tabs.ts"],"sourcesContent":["\"use client\"\n\nimport type { KeyboardEvent } from \"react\"\nimport type { HTMLProps, Orientation, PropGetter } from \"../../core\"\nimport { useCallback, useId, useState } from \"react\"\nimport { useControllableState } from \"../../hooks/use-controllable-state\"\nimport { createDescendants } from \"../../hooks/use-descendants\"\nimport {\n createContext,\n cx,\n handlerAll,\n isUndefined,\n mergeRefs,\n runKeyAction,\n useUpdateEffect,\n} from \"../../utils\"\n\nconst {\n DescendantsContext: TabDescendantsContext,\n useDescendant: useTabDescendant,\n useDescendants: useTabDescendants,\n} = createDescendants<HTMLButtonElement>()\n\nexport { TabDescendantsContext, useTabDescendant, useTabDescendants }\n\nconst {\n DescendantsContext: TabPanelDescendantsContext,\n useDescendant: useTabPanelDescendant,\n useDescendants: useTabPanelDescendants,\n} = createDescendants<HTMLDivElement>()\n\nexport {\n TabPanelDescendantsContext,\n useTabPanelDescendant,\n useTabPanelDescendants,\n}\n\ninterface TabsContext\n extends Omit<\n UseTabsReturn,\n \"getRootProps\" | \"tabDescendants\" | \"tabPanelDescendants\"\n > {}\n\nconst [TabsContext, useTabsContext] = createContext<TabsContext>({\n name: \"TabsContext\",\n})\n\nexport { TabsContext, useTabsContext }\n\nexport interface UseTabsProps extends Omit<HTMLProps, \"onChange\"> {\n /**\n * The index of the selected tab.\n */\n defaultIndex?: number\n /**\n * The index of the selected tab.\n */\n index?: number\n /**\n * If `true`, the tabs will be manually activated and display its panel by pressing Space or Enter.\n *\n * If `false`, the tabs will be automatically activated and their panel is displayed when they receive focus.\n *\n * @default false\n */\n manual?: boolean\n /**\n * The orientation of the tabs.\n *\n * @default 'horizontal'\n */\n orientation?: Orientation\n /**\n * The callback invoked when the index changes.\n */\n onChange?: (index: number) => void\n}\n\nexport const useTabs = ({\n id,\n defaultIndex = 0,\n index: indexProp,\n manual = false,\n orientation = \"horizontal\",\n onChange,\n ...rest\n}: UseTabsProps = {}) => {\n const uuid = useId()\n const tabDescendants = useTabDescendants()\n const tabPanelDescendants = useTabPanelDescendants()\n const [index, setIndex] = useControllableState({\n defaultValue: defaultIndex,\n value: indexProp,\n onChange,\n })\n const [focusedIndex, setFocusedIndex] = useState<number>(index)\n const horizontal = orientation === \"horizontal\"\n\n id ??= uuid\n\n const onFocusFirstTab = useCallback(() => {\n const first = tabDescendants.enabledFirstValue()\n\n if (first) first.node.focus()\n }, [tabDescendants])\n\n const onFocusLastTab = useCallback(() => {\n const last = tabDescendants.enabledLastValue()\n\n if (last) last.node.focus()\n }, [tabDescendants])\n\n const onFocusNextTab = useCallback(() => {\n const next = tabDescendants.enabledNextValue(focusedIndex)\n\n if (next) next.node.focus()\n }, [tabDescendants, focusedIndex])\n\n const onFocusPrevTab = useCallback(() => {\n const prev = tabDescendants.enabledPrevValue(focusedIndex)\n\n if (prev) prev.node.focus()\n }, [tabDescendants, focusedIndex])\n\n const onKeyDown = useCallback(\n (ev: KeyboardEvent<HTMLDivElement>) => {\n runKeyAction(ev, {\n ArrowDown: !horizontal ? onFocusNextTab : undefined,\n ArrowLeft: horizontal ? onFocusPrevTab : undefined,\n ArrowRight: horizontal ? onFocusNextTab : undefined,\n ArrowUp: !horizontal ? onFocusPrevTab : undefined,\n End: onFocusLastTab,\n Home: onFocusFirstTab,\n })\n },\n [\n horizontal,\n onFocusNextTab,\n onFocusPrevTab,\n onFocusLastTab,\n onFocusFirstTab,\n ],\n )\n\n useUpdateEffect(() => {\n if (isUndefined(indexProp)) return\n\n setIndex(indexProp)\n setFocusedIndex(indexProp)\n }, [indexProp])\n\n const getRootProps: PropGetter = useCallback(\n ({ ref, ...props } = {}) => ({\n \"data-orientation\": orientation,\n ...rest,\n ...props,\n ref: mergeRefs(ref, rest.ref),\n }),\n [orientation, rest],\n )\n\n const getListProps: PropGetter = useCallback(\n (props = {}) => ({\n \"aria-orientation\": orientation,\n role: \"tablist\",\n ...props,\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown),\n }),\n [orientation, onKeyDown],\n )\n\n return {\n id,\n focusedIndex,\n index,\n manual,\n orientation,\n setFocusedIndex,\n setIndex,\n tabDescendants,\n tabPanelDescendants,\n getListProps,\n getRootProps,\n }\n}\n\nexport type UseTabsReturn = ReturnType<typeof useTabs>\n\nexport interface UseTabProps extends HTMLProps<\"button\"> {\n /**\n * The index of the tab.\n */\n index: number\n}\n\nexport const useTab = ({ id, disabled, index, ...rest }: UseTabProps) => {\n const {\n id: rootId,\n index: selectedIndex,\n manual,\n orientation,\n setFocusedIndex,\n setIndex,\n } = useTabsContext()\n const { register } = useTabDescendant({ disabled })\n const tabPanelId = `${rootId}-panel-${index}`\n const selected = index === selectedIndex\n\n id ??= `${rootId}-tab-${index}`\n\n const onClick = useCallback(() => {\n if (!disabled) setIndex(index)\n }, [index, setIndex, disabled])\n\n const onFocus = useCallback(() => {\n if (disabled) return\n\n setFocusedIndex(index)\n\n if (!manual) setIndex(index)\n }, [setFocusedIndex, index, manual, disabled, setIndex])\n\n const getRootProps: PropGetter<\"button\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n id,\n type: \"button\",\n \"aria-controls\": tabPanelId,\n \"aria-selected\": selected,\n \"data-orientation\": orientation,\n disabled,\n role: \"tab\",\n tabIndex: selected ? 0 : -1,\n ...rest,\n ...props,\n ref: mergeRefs(ref, register),\n onClick: handlerAll(props.onClick, rest.onClick, onClick),\n onFocus: handlerAll(props.onFocus, rest.onFocus, onFocus),\n }),\n [\n disabled,\n id,\n onClick,\n onFocus,\n orientation,\n register,\n rest,\n selected,\n tabPanelId,\n ],\n )\n\n return { index, selected, getRootProps }\n}\n\nexport type UseTabReturn = ReturnType<typeof useTab>\n\nexport interface UseTabPanelProps extends HTMLProps {\n /**\n * The index of the tab panel.\n */\n index: number\n}\n\nexport const useTabPanel = ({\n id,\n \"aria-labelledby\": ariaLabelledbyProp,\n index,\n ...rest\n}: UseTabPanelProps) => {\n const { id: rootId, index: selectedIndex, orientation } = useTabsContext()\n const { register } = useTabPanelDescendant()\n const tabId = `${rootId}-tab-${index}`\n const selected = index === selectedIndex\n\n id ??= `${rootId}-panel-${index}`\n\n const getRootProps: PropGetter = useCallback(\n ({ ref, \"aria-labelledby\": ariaLabelledby, ...props } = {}) => ({\n id,\n \"aria-labelledby\": cx(ariaLabelledbyProp, ariaLabelledby, tabId),\n \"data-orientation\": orientation,\n hidden: !selected,\n role: \"tabpanel\",\n tabIndex: selected ? 0 : -1,\n ...rest,\n ...props,\n ref: mergeRefs(ref, register),\n }),\n [id, ariaLabelledbyProp, orientation, register, rest, selected, tabId],\n )\n\n return { index, selected, getRootProps }\n}\n\nexport type UseTabPanelReturn = ReturnType<typeof useTabPanel>\n"],"mappings":"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"}