chakra-ui-docs icon indicating copy to clipboard operation
chakra-ui-docs copied to clipboard

Document how to use Alert Dialog with TypeScript

Open adamzerner opened this issue 2 years ago • 3 comments

Subject

Alert Dialog

Description

The docs for Alert Dialog don't show how to use it with TypeScript, and TypeScript usage is a little counterintuitive. (Roughly) following the docs like this:

const UnsubscribeAlert = ({
  isOpen,
  onClose,
  onUnsubscribe,
  isUnsubscribing,
}: {
  isOpen: boolean;
  onClose: () => void;
  onUnsubscribe: () => void;
  isUnsubscribing: boolean;
}) => {
  const cancelRef = useRef();

  return (
    <AlertDialog
      isOpen={isOpen}
      leastDestructiveRef={cancelRef}
      onClose={onClose}
    >
      <AlertDialogOverlay>
        <AlertDialogContent>
          <AlertDialogHeader fontSize="lg" fontWeight="bold">
            Unsubscribe
          </AlertDialogHeader>

          <AlertDialogBody>
            Are you sure? If you unsubscribe you will retain access until your
            current subscription ends. After that you will lose access to all
            but the first 10 entries you created and be unable to create new
            ones.
          </AlertDialogBody>

          <AlertDialogFooter>
            <Button ref={cancelRef} onClick={onClose}>
              Cancel
            </Button>
            <Button
              colorScheme="red"
              onClick={onUnsubscribe}
              ml={3}
              disabled={isUnsubscribing}
              isLoading={isUnsubscribing}
              loadingText="Unsubscribing..."
            >
              Unsubscribe
            </Button>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialogOverlay>
    </AlertDialog>
  );
};

Gives the following error for leastDestructiveRef:

Type 'MutableRefObject<undefined>' is not assignable to type 'RefObject<FocusableElement>'.
  Types of property 'current' are incompatible.
    Type 'undefined' is not assignable to type 'FocusableElement | null'.ts(2322)

and for ref:

Type 'MutableRefObject<undefined>' is not assignable to type 'LegacyRef<HTMLButtonElement> | undefined'.
  Type 'MutableRefObject<undefined>' is not assignable to type 'RefObject<HTMLButtonElement>'.
    Types of property 'current' are incompatible.
      Type 'undefined' is not assignable to type 'HTMLButtonElement | null'.ts(2322)

Doing cancelRef.current = null; doesn't fix it. The first two errors remain unchanged and the line for cancelRef.current = null; has an error of:

Type 'null' is not assignable to type 'undefined'.

Doing useRef<null>() fixes that third error but not the first two.

It looks like leastDestructiveRef wants RefObject<FocusableElement>. I see that RefObject can be imported from React but I'm not sure where to get FocusableElement. VSCode doesn't provide any recommendations. So I ended up doing this which got rid of the errors but isn't ideal.

const cancelRef: RefObject<any> = useRef();

adamzerner avatar Jan 26 '23 06:01 adamzerner

Hello,

FocusableElement is any focusable element (element or other, exposing a focus() method), in our case a button.

So you should use HTMLButtonElement for typing your ref. You also need to type your ref with null to comply with leastDestructiveRef and ref props typing, you can do something like that :

const buttonRef = useRef<HTMLButtonElement>(null);

TypeScript will infer null type from default value.

Gregory-Gerard avatar Feb 02 '23 13:02 Gregory-Gerard

Gotcha, thanks.

adamzerner avatar Feb 04 '23 23:02 adamzerner

Hi! This issue has been automatically marked as stale because lack of recent activity. It will be closed if no further activity occurs within 5 days. Thank you for your contributions.

stale[bot] avatar May 21 '23 20:05 stale[bot]