UNPKG

@crossed/ui

Version:

A universal & performant styling library for React Native, Next.js & React

175 lines (174 loc) 4.52 kB
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