@stratakit/structures
Version:
Medium-sized component structures for the Strata design system
99 lines (98 loc) • 2.79 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import { useStoreState } from "@ariakit/react/store";
import * as AkTab from "@ariakit/react/tab";
import {
forwardRef,
isBrowser,
useUnreactiveCallback
} from "@stratakit/foundations/secret-internals";
import cx from "classnames";
const supportsAnchorPositioning = isBrowser && CSS?.supports("anchor-name: --foo");
const prefersReducedMotion = () => isBrowser && window.matchMedia("(prefers-reduced-motion)").matches;
function Tabs(props) {
const {
defaultSelectedId,
selectedId,
setSelectedId,
selectOnMove,
children
} = props;
const store = AkTab.useTabStore({ defaultSelectedId });
const tablist = useStoreState(store, "baseElement");
const selectedIdFromStore = useStoreState(store, "selectedId");
const flipAnimateStripe = (newSelectedId) => {
if (!supportsAnchorPositioning) return;
const rootNode = tablist?.getRootNode();
if (!rootNode || !selectedIdFromStore || !newSelectedId) return;
const previousTabRect = rootNode.getElementById?.(selectedIdFromStore)?.getBoundingClientRect();
const nextTabRect = rootNode.getElementById?.(newSelectedId)?.getBoundingClientRect();
if (!previousTabRect || !nextTabRect) return;
const deltaX = previousTabRect.left - nextTabRect.left;
const deltaWidth = previousTabRect.width / nextTabRect.width;
tablist?.animate(
[
{ transform: `translateX(${deltaX}px) scaleX(${deltaWidth})` },
{ transform: "none" }
],
{
pseudoElement: "::after",
duration: 150,
easing: "ease-in-out"
}
);
};
return /* @__PURE__ */ jsx(
AkTab.TabProvider,
{
store,
selectedId,
setSelectedId: useUnreactiveCallback(
(newSelectedId) => {
if (!prefersReducedMotion()) flipAnimateStripe(newSelectedId);
setSelectedId?.(newSelectedId);
}
),
selectOnMove,
children
}
);
}
const TabList = forwardRef((props, forwardedRef) => {
const { tone = "neutral", ...rest } = props;
return /* @__PURE__ */ jsx(
AkTab.TabList,
{
...rest,
"data-kiwi-tone": tone,
className: cx("\u{1F95D}-tab-list", props.className),
ref: forwardedRef
}
);
});
const Tab = forwardRef((props, forwardedRef) => {
return /* @__PURE__ */ jsx(
AkTab.Tab,
{
accessibleWhenDisabled: true,
...props,
className: cx("\u{1F95D}-tab", props.className),
ref: forwardedRef
}
);
});
const TabPanel = forwardRef((props, forwardedRef) => {
return /* @__PURE__ */ jsx(
AkTab.TabPanel,
{
...props,
className: cx("\u{1F95D}-tab-panel", props.className),
ref: forwardedRef
}
);
});
export {
Tabs as Root,
Tab,
TabList,
TabPanel
};