@crossed/ui
Version:
A universal & performant styling library for React Native, Next.js & React
151 lines (150 loc) • 4.22 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import { composeEventHandlers, withStaticProperties } from "@crossed/core";
import {
useCallback,
useEffect,
useRef
} from "react";
import {
composeStyles,
isWeb,
useInteraction
} from "@crossed/styled";
import { withTiming } from "react-native-reanimated";
import { focusStyles, tabTitleStyles, triggerStyles } from "./styles";
import { Button } from "../../buttons/Button";
import { useMedia } from "../../useMedia";
const createTab = ({
useTriggerContext,
useTabsContext,
TriggerProvider
}) => {
const TabImpl = ({
value: valueProps,
children,
disabled,
style,
...props
}) => {
const {
setValue,
value,
id,
variant,
listTabRef,
indicator,
scroll,
shouldShow,
widthLayout,
size
} = useTabsContext();
const media = useMedia();
const selected = valueProps === value;
const { state, props: interaction } = useInteraction(props);
const measure = () => {
var _a;
if (listTabRef.current) {
(_a = ref.current) == null ? void 0 : _a.measureLayout(
listTabRef.current,
(left, _top, width) => {
var _a2, _b;
const offset = shouldShow ? 30 : 0;
const positionLeft = isWeb ? left + scroll.value : left;
indicator.left.value = withTiming(positionLeft);
indicator.width.value = withTiming(width);
if (widthLayout.value + scroll.value < positionLeft + width + offset) {
(_a2 = listTabRef.current) == null ? void 0 : _a2.scrollTo({
x: positionLeft + width - widthLayout.value + offset
});
} else if (positionLeft <= offset || positionLeft < scroll.value) {
(_b = listTabRef.current) == null ? void 0 : _b.scrollTo({
x: positionLeft - offset
});
}
}
);
}
};
const onPress = useCallback(
composeEventHandlers(() => {
setValue(valueProps);
measure();
}, props.onPress),
[props.onPress, setValue]
);
useEffect(() => {
if (shouldShow && selected) {
measure();
}
}, [shouldShow]);
useEffect(() => {
selected && measure();
}, [...Object.values(media), selected]);
const onLayout = useCallback(
composeEventHandlers(({ nativeEvent: { layout } }) => {
if (selected) {
indicator.left.value = layout.x + scroll.value;
indicator.width.value = layout.width;
}
}, props.onLayout),
[props.onLayout, setValue, selected, shouldShow]
);
const ref = useRef();
return /* @__PURE__ */ jsx(
TriggerProvider,
{
...state,
disabled,
selected,
hover: selected || state.hover,
children: /* @__PURE__ */ jsx(
Button,
{
role: "tab",
ref,
disabled,
variant: "tertiary",
"aria-selected": selected,
"aria-control": `${id}-panel-${valueProps}`,
id: `${id}-tab-${valueProps}`,
...props,
style: composeStyles(
triggerStyles.trigger,
triggerStyles[size],
focusStyles[variant],
disabled && triggerStyles.disabled,
style
),
...interaction,
onPress,
onLayout,
children: (e) => typeof children === "function" ? children(e) : children
}
)
}
);
};
const Text = ({ style, ...props }) => {
const { size } = useTabsContext();
const state = useTriggerContext();
return /* @__PURE__ */ jsx(
Button.Text,
{
style: composeStyles(
tabTitleStyles.default,
state.selected && tabTitleStyles.active,
!state.selected && !state.disabled && state.hover && tabTitleStyles.hover,
style
),
size: size === "sm" ? "md" : "default",
...state,
...props
}
);
};
return withStaticProperties(TabImpl, { Text });
};
export {
createTab
};
//# sourceMappingURL=Tab.js.map