@ariakit/react-core
Version:
Ariakit React core
195 lines (193 loc) • 5.95 kB
JavaScript
"use client";
import {
TabScopedContextProvider,
useTabProviderContext
} from "../__chunks/QGC5LOGZ.js";
import {
useDisclosureContent
} from "../__chunks/K4R5DNTX.js";
import {
useDisclosureStore
} from "../__chunks/T22PY7TE.js";
import {
useCollectionItem
} from "../__chunks/Y62RTBST.js";
import "../__chunks/T2AZQXQU.js";
import "../__chunks/ABN76PSX.js";
import "../__chunks/APTFW6PT.js";
import {
useFocusable
} from "../__chunks/OE2EFRVA.js";
import "../__chunks/SWN3JYXT.js";
import {
useStoreState
} from "../__chunks/RTNCFSKZ.js";
import "../__chunks/5CPL3B7G.js";
import {
createElement,
createHook,
forwardRef
} from "../__chunks/VOQWLFSQ.js";
import {
useEvent,
useId,
useMergeRefs,
useWrapElement
} from "../__chunks/5GGHRIN3.js";
import "../__chunks/SK3NAZA3.js";
import {
__objRest,
__spreadProps,
__spreadValues
} from "../__chunks/3YLGPPWQ.js";
// src/tab/tab-panel.tsx
import { getAllTabbableIn } from "@ariakit/core/utils/focus";
import { invariant } from "@ariakit/core/utils/misc";
import { useCallback, useEffect, useRef, useState } from "react";
import { jsx } from "react/jsx-runtime";
var TagName = "div";
var useTabPanel = createHook(
function useTabPanel2(_a) {
var _b = _a, {
store,
unmountOnHide,
tabId: tabIdProp,
getItem: getItemProp,
scrollRestoration,
scrollElement
} = _b, props = __objRest(_b, [
"store",
"unmountOnHide",
"tabId",
"getItem",
"scrollRestoration",
"scrollElement"
]);
const context = useTabProviderContext();
store = store || context;
invariant(
store,
process.env.NODE_ENV !== "production" && "TabPanel must receive a `store` prop or be wrapped in a TabProvider component."
);
const ref = useRef(null);
const id = useId(props.id);
const tabId = useStoreState(
store.panels,
() => {
var _a2;
return tabIdProp || ((_a2 = store == null ? void 0 : store.panels.item(id)) == null ? void 0 : _a2.tabId);
}
);
const open = useStoreState(
store,
(state) => !!tabId && state.selectedId === tabId
);
const disclosure = useDisclosureStore({ open });
const mounted = useStoreState(disclosure, "mounted");
const scrollPositionRef = useRef(
/* @__PURE__ */ new Map()
);
const getScrollElement = useEvent(() => {
const panelElement = ref.current;
if (!panelElement) return null;
if (!scrollElement) return panelElement;
if (typeof scrollElement === "function") {
return scrollElement(panelElement);
}
if ("current" in scrollElement) {
return scrollElement.current;
}
return scrollElement;
});
useEffect(() => {
var _a2, _b2;
if (!scrollRestoration) return;
if (!mounted) return;
const element = getScrollElement();
if (!element) return;
if (scrollRestoration === "reset") {
element.scroll(0, 0);
return;
}
if (!tabId) return;
const position = scrollPositionRef.current.get(tabId);
element.scroll((_a2 = position == null ? void 0 : position.x) != null ? _a2 : 0, (_b2 = position == null ? void 0 : position.y) != null ? _b2 : 0);
const onScroll = () => {
scrollPositionRef.current.set(tabId, {
x: element.scrollLeft,
y: element.scrollTop
});
};
element.addEventListener("scroll", onScroll);
return () => {
element.removeEventListener("scroll", onScroll);
};
}, [scrollRestoration, mounted, tabId, getScrollElement, store]);
const [hasTabbableChildren, setHasTabbableChildren] = useState(false);
useEffect(() => {
const element = ref.current;
if (!element) return;
const tabbable = getAllTabbableIn(element);
setHasTabbableChildren(!!tabbable.length);
}, []);
const getItem = useCallback(
(item) => {
const nextItem = __spreadProps(__spreadValues({}, item), { id: id || item.id, tabId: tabIdProp });
if (getItemProp) {
return getItemProp(nextItem);
}
return nextItem;
},
[id, tabIdProp, getItemProp]
);
const onKeyDownProp = props.onKeyDown;
const onKeyDown = useEvent((event) => {
onKeyDownProp == null ? void 0 : onKeyDownProp(event);
if (event.defaultPrevented) return;
if (!(store == null ? void 0 : store.composite)) return;
const keyMap = {
ArrowLeft: store.previous,
ArrowRight: store.next,
Home: store.first,
End: store.last
};
const action = keyMap[event.key];
if (!action) return;
const { selectedId } = store.getState();
const nextId = action({ activeId: selectedId });
if (!nextId) return;
event.preventDefault();
store.move(nextId);
});
props = useWrapElement(
props,
(element) => /* @__PURE__ */ jsx(TabScopedContextProvider, { value: store, children: element }),
[store]
);
props = __spreadProps(__spreadValues({
id,
role: "tabpanel",
"aria-labelledby": tabId || void 0
}, props), {
children: unmountOnHide && !mounted ? null : props.children,
ref: useMergeRefs(ref, props.ref),
onKeyDown
});
props = useFocusable(__spreadValues({
// If the tab panel is rendered as part of another composite widget such
// as combobox, it should not be focusable.
focusable: !store.composite && !hasTabbableChildren
}, props));
props = useDisclosureContent(__spreadValues({ store: disclosure }, props));
props = useCollectionItem(__spreadProps(__spreadValues({ store: store.panels }, props), { getItem }));
return props;
}
);
var TabPanel = forwardRef(function TabPanel2(props) {
const htmlProps = useTabPanel(props);
return createElement(TagName, htmlProps);
});
export {
TabPanel,
useTabPanel
};