@stratakit/react
Version:
A React component library for StrataKit
225 lines (224 loc) • 6.64 kB
JavaScript
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 })
]
}
);
});
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
] });
});
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 })
}
)
}
);
});
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 });
});
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 });
});
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 });
});
const TabIcon = React.forwardRef((props, forwardedRef) => {
return /* @__PURE__ */ jsx(Icon, { ...props, ref: forwardedRef });
});
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
};