From 333220a15356111bdd19d77e5c160e846c684c40 Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Thu, 26 Mar 2026 12:58:24 -0400 Subject: [PATCH] feat: ditch react-aria --- app/components/dialog.tsx | 164 ++-- app/components/table-list.tsx | 4 +- app/components/tabs.tsx | 8 +- app/tailwind.css | 1 - package.json | 3 - pnpm-lock.yaml | 1701 --------------------------------- 6 files changed, 62 insertions(+), 1819 deletions(-) diff --git a/app/components/dialog.tsx b/app/components/dialog.tsx index 91e2203..29e9537 100644 --- a/app/components/dialog.tsx +++ b/app/components/dialog.tsx @@ -1,100 +1,62 @@ +import { AlertDialog } from "@base-ui/react/alert-dialog"; import React, { cloneElement, useEffect, useRef } from "react"; -import { - type AriaDialogProps, - type AriaModalOverlayProps, - Overlay, - useDialog, - useModalOverlay, - useOverlayTrigger, -} from "react-aria"; import { Form, type HTMLFormMethod } from "react-router"; -import { - type OverlayTriggerProps, - type OverlayTriggerState, - useOverlayTriggerState, -} from "react-stately"; -import Button, { ButtonProps } from "~/components/button"; +import Button, { type ButtonProps } from "~/components/button"; import cn from "~/utils/cn"; import { useLiveData } from "~/utils/live-data"; -export interface DialogProps extends OverlayTriggerProps { +export interface DialogProps { children: | [React.ReactElement, React.ReactElement] | React.ReactElement; + isOpen?: boolean; + onOpenChange?: (isOpen: boolean) => void; } function Dialog(props: DialogProps) { const { pause, resume } = useLiveData(); - const state = useOverlayTriggerState(props); - const { triggerProps, overlayProps } = useOverlayTrigger( - { - type: "dialog", - }, - state, - ); + const { isOpen, onOpenChange } = props; useEffect(() => { - if (state.isOpen) { + if (isOpen) { pause(); } else { resume(); } - }, [state.isOpen]); + }, [isOpen]); if (Array.isArray(props.children)) { const [button, panel] = props.children; - const buttonTriggerProps = { onClick: triggerProps.onPress } as Record; return ( - <> - {cloneElement(button, buttonTriggerProps)} - {state.isOpen && ( - - {cloneElement(panel, { - ...overlayProps, - close: () => state.close(), - })} - - )} - + onOpenChange?.(open)}> + + {panel} + ); } return ( - - {cloneElement(props.children, { - ...overlayProps, - close: () => state.close(), - })} - + onOpenChange?.(open)}> + {props.children} + ); } -export interface DialogPanelProps extends AriaDialogProps { +export interface DialogPanelProps { children: React.ReactNode; variant?: "normal" | "destructive" | "unactionable"; onSubmit?: React.FormEventHandler; method?: HTMLFormMethod; isDisabled?: boolean; - - // Anonymous (passed by parent) - close?: () => void; } function Panel(props: DialogPanelProps) { - const { children, onSubmit, isDisabled, close, variant, method = "POST" } = props; - const ref = useRef(null); - const { dialogProps } = useDialog( - { - ...props, - role: "alertdialog", - }, - ref, - ); + const { children, onSubmit, isDisabled, variant, method = "POST" } = props; + const closeRef = useRef(null); return ( -
{ - if (onSubmit) { - onSubmit(event); - } - - close?.(); - }} - ref={ref} > -
{children}
-
- {variant === "unactionable" ? ( - - ) : ( - <> - - - - )} -
-
+
{ + if (onSubmit) { + onSubmit(event); + } + + if (!event.defaultPrevented) { + closeRef.current?.click(); + } + }} + > +
{children}
+
+ {variant === "unactionable" ? ( + Close} /> + ) : ( + <> + Cancel} /> + + + + )} +
+
+ ); } -interface DModalProps extends AriaModalOverlayProps { - children: React.ReactNode; - state: OverlayTriggerState; -} - -function DModal(props: DModalProps) { - const { children, state } = props; - const ref = useRef(null); - const { modalProps, underlayProps } = useModalOverlay(props, state, ref); - - if (!state.isOpen) { - return null; - } - +function DialogOverlay({ children }: { children: React.ReactNode }) { return ( - -