UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

115 lines (113 loc) 4.08 kB
'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; import { useComponentRenderer } from '../../utils/useComponentRenderer.js'; import { useOnMount } from '../../utils/useOnMount.js'; import { useTabsRootContext } from '../root/TabsRootContext.js'; import { tabsStyleHookMapping } from '../root/styleHooks.js'; import { useTabsListContext } from '../list/TabsListContext.js'; import { useTabsIndicator } from './useTabsIndicator.js'; import { script as prehydrationScript } from './prehydrationScript.min.js'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const noop = () => null; /** * A visual indicator that can be styled to match the position of the currently active tab. * Renders a `<span>` element. * * Documentation: [Base UI Tabs](https://base-ui.com/react/components/tabs) */ const TabsIndicator = /*#__PURE__*/React.forwardRef(function TabIndicator(props, forwardedRef) { const { className, render, renderBeforeHydration = false, ...other } = props; const { getTabElementBySelectedValue, orientation, tabActivationDirection, value } = useTabsRootContext(); const { tabsListRef } = useTabsListContext(); const [instanceId] = React.useState(() => Math.random().toString(36).slice(2)); const [isMounted, setIsMounted] = React.useState(false); const { value: activeTabValue } = useTabsRootContext(); useOnMount(() => setIsMounted(true)); const { getRootProps, activeTabPosition: selectedTabPosition } = useTabsIndicator({ getTabElementBySelectedValue, tabsListRef, value }); const state = React.useMemo(() => ({ orientation, selectedTabPosition, tabActivationDirection }), [orientation, selectedTabPosition, tabActivationDirection]); const { renderElement } = useComponentRenderer({ propGetter: getRootProps, render: render ?? 'span', className, state, extraProps: { ...other, 'data-instance-id': !(isMounted && renderBeforeHydration) ? instanceId : undefined, suppressHydrationWarning: true }, customStyleHookMapping: { ...tabsStyleHookMapping, selectedTabPosition: noop }, ref: forwardedRef }); if (activeTabValue == null) { return null; } return /*#__PURE__*/_jsxs(React.Fragment, { children: [renderElement(), !isMounted && renderBeforeHydration && /*#__PURE__*/_jsx("script", { // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML: { __html: prehydrationScript }, suppressHydrationWarning: true })] }); }); export { TabsIndicator }; process.env.NODE_ENV !== "production" ? TabsIndicator.propTypes /* remove-proptypes */ = { // ┌────────────────────────────── Warning ──────────────────────────────┐ // │ These PropTypes are generated from the TypeScript type definitions. │ // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │ // └─────────────────────────────────────────────────────────────────────┘ /** * @ignore */ children: PropTypes.node, /** * CSS class applied to the element, or a function that * returns a class based on the component’s state. */ className: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** * Allows you to replace the component’s HTML element * with a different tag, or compose it with another component. * * Accepts a `ReactElement` or a function that returns the element to render. */ render: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), /** * Whether to render itself before React hydrates. * This minimizes the time that the indicator isn’t visible after server-side rendering. * @default false */ renderBeforeHydration: PropTypes.bool } : void 0;