import * as Collapsible from '@radix-ui/react-collapsible';
useIsomorphicLayoutEffect,
} from '~/components/primitives/hooks';
import * as Slot from '~/components/primitives/slot';
import * as React from 'react';
import { Pressable, View, type GestureResponderEvent } from 'react-native';
const CollapsibleContext = React.createContext<RootContext | null>(null);
const Root = React.forwardRef<RootRef, RootProps>(
onOpenChange: onOpenChangeProp,
const [open = false, onOpenChange] = useControllableState({
defaultProp: defaultOpen,
onChange: onOpenChangeProp,
const augmentedRef = useAugmentedRef({ ref });
useIsomorphicLayoutEffect(() => {
if (augmentedRef.current) {
const augRef = augmentedRef.current as unknown as HTMLDivElement;
augRef.dataset.state = open ? 'open' : 'closed';
useIsomorphicLayoutEffect(() => {
if (augmentedRef.current) {
const augRef = augmentedRef.current as unknown as HTMLDivElement;
augRef.dataset.disabled = 'true';
augRef.dataset.disabled = undefined;
const Component = asChild ? Slot.View : View;
<CollapsibleContext.Provider
defaultOpen={defaultOpen}
onOpenChange={onOpenChange}
<Component ref={ref} {...viewProps} />
</CollapsibleContext.Provider>
Root.displayName = 'RootWebCollapsible';
function useCollapsibleContext() {
const context = React.useContext(CollapsibleContext);
'Collapsible compound components cannot be rendered outside the Collapsible component'
const Trigger = React.forwardRef<TriggerRef, TriggerProps>(
({ asChild, onPress: onPressProp, disabled: disabledProp = false, ...props }, ref) => {
const { disabled, open, onOpenChange } = useCollapsibleContext();
const augmentedRef = useAugmentedRef({ ref });
useIsomorphicLayoutEffect(() => {
if (augmentedRef.current) {
const augRef = augmentedRef.current as unknown as HTMLButtonElement;
augRef.dataset.state = open ? 'open' : 'closed';
useIsomorphicLayoutEffect(() => {
if (augmentedRef.current) {
const augRef = augmentedRef.current as unknown as HTMLButtonElement;
augRef.dataset.disabled = 'true';
augRef.dataset.disabled = undefined;
function onPress(ev: GestureResponderEvent) {
const Component = asChild ? Slot.Pressable : Pressable;
<Collapsible.Trigger disabled={disabled} asChild>
Trigger.displayName = 'TriggerWebCollapsible';
const Content = React.forwardRef<ContentRef, ContentProps>(
({ asChild, forceMount, ...props }, ref) => {
const augmentedRef = useAugmentedRef({ ref });
const { open } = useCollapsibleContext();
useIsomorphicLayoutEffect(() => {
if (augmentedRef.current) {
const augRef = augmentedRef.current as unknown as HTMLDivElement;
augRef.dataset.state = open ? 'open' : 'closed';
const Component = asChild ? Slot.View : View;
<Collapsible.Content forceMount={forceMount} asChild>
<Component ref={augmentedRef} {...props} />
Content.displayName = 'ContentWebCollapsible';
export { Content, Root, Trigger };