UNPKG

@stratakit/react

Version:

A React component library for StrataKit

232 lines (231 loc) 6.91 kB
import { jsx, jsxs } from "react/jsx-runtime"; import * as React from "react"; import { useControlledState, useSafeContext } from "@stratakit/foundations/secret-internals"; import { Tabs as SkTabs } from "@stratakit/structures"; import cx from "classnames"; import { useCompatProps } from "./~utils.js"; import { Icon } from "./Icon.js"; const LegacyTabs = React.forwardRef((props, forwardedRef) => { const { labels, onTabSelected, activeIndex: activeIndexProp, focusActivationMode, color, tabsClassName, contentClassName, wrapperClassName, children, overflowOptions: _overflowOptions, // ignored by iTwinUI defaultValue: _defaultValue, // ignored by iTwinUI defaultChecked: _defaultChecked, // ignored by iTwinUI // biome-ignore-start lint/correctness/noUnusedVariables: NOT IMPLEMENTED actions, orientation, type, // biome-ignore-end lint/correctness/noUnusedVariables: NOT IMPLEMENTED ...rest } = useCompatProps(props); const [activeIndex, setActiveIndex] = useControlledState( 0, activeIndexProp, onTabSelected ); const onValueChange = React.useCallback( (newValue) => { const newActiveIndex = Number(newValue); setActiveIndex(newActiveIndex); }, [setActiveIndex] ); const value = `${activeIndex}`; return /* @__PURE__ */ jsxs( Wrapper, { ...rest, className: cx(wrapperClassName, props.className), value, onValueChange, color, focusActivationMode, children: [ /* @__PURE__ */ jsx(TabList, { className: tabsClassName, ref: forwardedRef, children: labels.map((label, index) => { const key = getLabelKey(label, index); const tabValue = `${index}`; return /* @__PURE__ */ jsx(LegacyTabProvider, { tabValue, children: typeof label === "string" ? /* @__PURE__ */ jsx(LegacyTab, { label }) : label }, key); }) }), /* @__PURE__ */ jsx(Panel, { value, className: contentClassName, children }) ] } ); }); DEV: LegacyTabs.displayName = "Tabs"; function getLabelKey(label, index) { if (typeof label === "string") { return `${index}-${label}`; } if (React.isValidElement(label)) { return `${index}-${label.key || ""}-${label.props.id || ""}`; } return `${index}`; } const LegacyTab = React.forwardRef((props, forwardedRef) => { const { id: _id, // ignored by iTwinUI label, disabled, startIcon, // biome-ignore-start lint/correctness/noUnusedVariables: NOT IMPLEMENTED sublabel, children, value, // biome-ignore-end lint/correctness/noUnusedVariables: NOT IMPLEMENTED ...rest } = useCompatProps(props); const { tabValue } = useSafeContext(LegacyTabContext); return /* @__PURE__ */ jsxs(Tab, { ...rest, value: tabValue, disabled, ref: forwardedRef, children: [ startIcon ? /* @__PURE__ */ jsx(TabIcon, { children: startIcon }) : null, label ] }); }); DEV: LegacyTab.displayName = "Tab"; const LegacyTabContext = React.createContext(void 0); function LegacyTabProvider({ children, tabValue }) { return /* @__PURE__ */ jsx( LegacyTabContext.Provider, { value: React.useMemo(() => ({ tabValue }), [tabValue]), children } ); } const Wrapper = React.forwardRef((props, forwardedRef) => { const { children, color, focusActivationMode, defaultValue, value, onValueChange, defaultChecked: _defaultChecked, // ignored by iTwinUI // biome-ignore-start lint/correctness/noUnusedVariables: NOT IMPLEMENTED orientation, type, // biome-ignore-end lint/correctness/noUnusedVariables: NOT IMPLEMENTED ...rest } = useCompatProps(props); const wrapperId = React.useId(); const tone = color === "green" ? "accent" : void 0; const defaultSelectedId = defaultValue ? toIdFromValue(defaultValue, wrapperId) : void 0; const selectedId = value ? toIdFromValue(value, wrapperId) : void 0; const setSelectedId = React.useCallback( (newSelectedId) => { if (!onValueChange || !newSelectedId) return; const newSelectedValue = toValueFromId(newSelectedId, wrapperId); if (!newSelectedValue) return; onValueChange?.(newSelectedValue); }, [onValueChange, wrapperId] ); return /* @__PURE__ */ jsx( SkTabs.Root, { defaultSelectedId, selectedId, selectOnMove: focusActivationMode === "manual" ? false : void 0, setSelectedId, children: /* @__PURE__ */ jsx( WrapperContext.Provider, { value: React.useMemo(() => ({ tone, wrapperId }), [tone, wrapperId]), children: /* @__PURE__ */ jsx("div", { ...rest, ref: forwardedRef, children }) } ) } ); }); DEV: Wrapper.displayName = "Tabs.Wrapper"; const WrapperContext = React.createContext(void 0); const TabList = React.forwardRef((props, forwardedRef) => { const { children, ...rest } = useCompatProps(props); const { tone } = useSafeContext(WrapperContext); return /* @__PURE__ */ jsx(SkTabs.TabList, { ...rest, tone, ref: forwardedRef, children }); }); DEV: TabList.displayName = "Tabs.TabList"; const Tab = React.forwardRef((props, forwardedRef) => { const { children, value, label, id: _id, // ignored by iTwinUI ...rest } = useCompatProps(props); const id = useIdFromValue(value); return /* @__PURE__ */ jsx(SkTabs.Tab, { ...rest, id, ref: forwardedRef, children: label ?? children }); }); DEV: Tab.displayName = "Tabs.Tab"; const Panel = React.forwardRef((props, forwardedRef) => { const { children, value, id: _id, // ignored by iTwinUI ...rest } = useCompatProps(props); const tabId = useIdFromValue(value); return /* @__PURE__ */ jsx(SkTabs.TabPanel, { ...rest, tabId, ref: forwardedRef, children }); }); DEV: Panel.displayName = "Tabs.Panel"; const TabIcon = React.forwardRef((props, forwardedRef) => { return /* @__PURE__ */ jsx(Icon, { ...props, ref: forwardedRef }); }); DEV: TabIcon.displayName = "Tabs.TabIcon"; const TabLabel = React.forwardRef((_props, _forwardedRef) => { return null; }); const TabDescription = React.forwardRef((_props, _forwardedRef) => { return null; }); const Actions = React.forwardRef((_props, _forwardedRef) => { return null; }); const Tabs = Object.assign(LegacyTabs, { Wrapper, TabList, Tab, TabIcon, /** NOT IMPLEMENTED. */ TabLabel, /** NOT IMPLEMENTED. */ TabDescription, /** NOT IMPLEMENTED. */ Actions, Panel }); function toIdFromValue(value, wrapperId) { return `${wrapperId}-${value}`; } function toValueFromId(id, wrapperId) { if (!id.startsWith(`${wrapperId}-`)) return void 0; return id.slice(wrapperId.length + 1); } function useIdFromValue(value) { const { wrapperId } = useSafeContext(WrapperContext); return toIdFromValue(value, wrapperId); } export { LegacyTab as Tab, Tabs };