@crossed/ui
Version:
A universal & performant styling library for React Native, Next.js & React
175 lines (174 loc) • 4.52 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import {
composeStyles,
createStyles,
inlineStyle
} from "@crossed/styled";
import {
createContext,
forwardRef,
useCallback,
useContext,
useEffect,
useRef
} from "react";
import { ChevronDown } from "@crossed/unicons";
import {
ScrollView
} from "react-native";
import { useUncontrolled, withStaticProperties } from "@crossed/core";
import { Floating } from "../overlay/Floating";
import Animated, {
useAnimatedStyle,
useSharedValue,
withTiming
} from "react-native-reanimated";
import { useFloatingContext } from "../overlay/Floating/context";
const accordionStyles = createStyles((t) => ({
root: {
base: {
borderBottomWidth: 1,
borderColor: t.colors.border.primary,
borderStyle: "solid"
}
},
trigger: {
base: {
flexDirection: "row",
justifyContent: "space-between"
}
},
panel: {
web: {
base: { overflow: "hidden", transition: "height 170ms ease-out" }
}
},
item: {
base: {
borderTopWidth: 1,
borderColor: t.colors.border.primary,
borderStyle: "solid"
},
web: {
base: { transition: "height 1000ms ease" }
}
}
}));
const rootContext = createContext(
{}
);
const itemContext = createContext({});
const Root = (props) => {
const {
children,
allowMultiple = false,
defaultValues,
values: valueProps,
onChange
} = props;
const [values, setValues] = useUncontrolled({
defaultValue: defaultValues ?? [],
value: valueProps,
onChange
});
return /* @__PURE__ */ jsx(rootContext.Provider, { value: { values, setValues, allowMultiple }, children });
};
Root.displayName = "Accordion";
const AccordionItem = ({ children, value }) => {
const { setValues, values, allowMultiple } = useContext(rootContext);
const buttonId = useRef();
const panelId = useRef();
const handleChange = useCallback(() => {
setValues(
allowMultiple ? values.includes(value) ? values.filter((e) => e !== value) : [...values, value] : [value]
);
}, [setValues, value, values, allowMultiple]);
return /* @__PURE__ */ jsx(itemContext.Provider, { value: { value, buttonId, panelId }, children: /* @__PURE__ */ jsx(
Floating,
{
onChange: handleChange,
value: values.includes(value),
removeScroll: false,
children
}
) });
};
AccordionItem.displayName = "Accordion.Item";
const AccordionTrigger = forwardRef(
({ style, ...props }, ref) => /* @__PURE__ */ jsx(
Floating.Trigger,
{
...props,
ref,
style: composeStyles(accordionStyles.trigger, style)
}
)
);
AccordionTrigger.displayName = "Accordion.Trigger";
const AccordionPanel = ({ children, style, ...props }) => {
const openSharedValue = useSharedValue(false);
const { open } = useFloatingContext();
const height = useSharedValue(0);
const handleLayout = useCallback(
(_w, h) => {
height.value = h;
},
[height]
);
useEffect(() => {
openSharedValue.value = open;
}, [open]);
const animatedStyle = useAnimatedStyle(() => {
return {
height: withTiming(openSharedValue.value ? height.value : 0)
};
}, [height, openSharedValue]);
return /* @__PURE__ */ jsx(
Floating.VisibilityHidden,
{
animatedStyle,
style: composeStyles(
inlineStyle(() => ({
base: { position: "relative" }
})),
style
),
children: /* @__PURE__ */ jsx(
ScrollView,
{
onContentSizeChange: handleLayout,
...props,
style: { flex: 1 },
children
}
)
}
);
};
AccordionPanel.displayName = "Accordion.Panel";
const AccordionIcon = ({ style }) => {
const { value } = useContext(itemContext);
const { values } = useContext(rootContext);
const isOpen = values.includes(value);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ rotate: withTiming(isOpen ? "180deg" : "0deg") }]
};
}, [isOpen]);
return /* @__PURE__ */ jsx(Animated.View, { style: [style == null ? void 0 : style.style().style, animatedStyle], children: /* @__PURE__ */ jsx(ChevronDown, {}) });
};
AccordionIcon.displayName = "Accordion.Icon";
const Accordion = withStaticProperties(Root, {
Item: AccordionItem,
Panel: AccordionPanel,
Trigger: AccordionTrigger,
Icon: AccordionIcon
});
export {
Accordion,
AccordionIcon,
AccordionItem,
AccordionPanel,
AccordionTrigger
};
//# sourceMappingURL=Accordion.js.map