<commit_before>import {
  useState,
  useRef,
  useEffect,
  isValidElement,
  DOMAttributes
} from 'react';

import { isFn } from '../utils';
import { ToastProps } from '../types';
import { useKeeper } from './useKeeper';
import { Direction } from '../utils/constant';

interface Draggable {
  start: number;
  x: number;
  y: number;
  delta: number;
  removalDistance: number;
  canCloseOnClick: boolean;
  canDrag: boolean;
  boundingRect: DOMRect | null;
}

type DragEvent = MouseEvent & TouchEvent;

function getX(e: DragEvent) {
  return e.targetTouches && e.targetTouches.length >= 1
    ? e.targetTouches[0].clientX
    : e.clientX;
}

function getY(e: DragEvent) {
  return e.targetTouches && e.targetTouches.length >= 1
    ? e.targetTouches[0].clientY
    : e.clientY;
}

export function useToast(props: ToastProps) {
  const [isRunning, setIsRunning] = useState(true);
  const [preventExitTransition, setPreventExitTransition] = useState(false);
  const toastRef = useRef<HTMLDivElement>(null);
  const drag = useKeeper<Draggable>({
    start: 0,
    x: 0,
    y: 0,
    delta: 0,
    removalDistance: 0,
    canCloseOnClick: true,
    canDrag: false,
    boundingRect: null
  });
  const syncProps = useKeeper(props, true);
  const { autoClose, pauseOnHover, closeToast, onClick, closeOnClick } = props;

  useEffect(() => {
    if (isFn(props.onOpen))
      props.onOpen(isValidElement(props.children) && props.children.props);

    return () => {
      if (isFn(syncProps.onClose))
        syncProps.onClose(
          isValidElement(syncProps.children) && syncProps.children.props
        );
    };
  }, []);

  useEffect(() => {
    props.draggable && bindDragEvents();
    return () => {
      props.draggable && unbindDragEvents();
    };
  }, [props.draggable]);

  useEffect(() => {
    props.pauseOnFocusLoss && bindFocusEvents();
    return () => {
      props.pauseOnFocusLoss && unbindFocusEvents();
    };
  }, [props.pauseOnFocusLoss]);

  function onDragStart(
    e: React.MouseEvent<HTMLElement, MouseEvent> | React.TouchEvent<HTMLElement>
  ) {
    if (props.draggable) {
      const toast = toastRef.current!;
      drag.canCloseOnClick = true;
      drag.canDrag = true;
      drag.boundingRect = toast.getBoundingClientRect();
      toast.style.transition = '';

      if (props.draggableDirection === Direction.X) {
        drag.start = drag.x = getX(e.nativeEvent as DragEvent);
        drag.removalDistance =
          toast.offsetWidth * (props.draggablePercent / 100);
      } else {
        drag.start = drag.y = getY(e.nativeEvent as DragEvent);
        drag.removalDistance =
          toast.offsetHeight * (props.draggablePercent / 100);
      }
    }
  }

  function onDragTransitionEnd() {
    if (drag.boundingRect) {
      const { top, bottom, left, right } = drag.boundingRect;<commit_msg>fix #555<commit_after>import {
  useState,
  useRef,
  useEffect,
  isValidElement,
  DOMAttributes
} from 'react';

import { isFn } from '../utils';
import { ToastProps } from '../types';
import { useKeeper } from './useKeeper';
import { Direction } from '../utils/constant';

interface Draggable {
  start: number;
  x: number;
  y: number;
  delta: number;
  removalDistance: number;
  canCloseOnClick: boolean;
  canDrag: boolean;
  boundingRect: DOMRect | null;
}

type DragEvent = MouseEvent & TouchEvent;

function getX(e: DragEvent) {
  return e.targetTouches && e.targetTouches.length >= 1
    ? e.targetTouches[0].clientX
    : e.clientX;
}

function getY(e: DragEvent) {
  return e.targetTouches && e.targetTouches.length >= 1
    ? e.targetTouches[0].clientY
    : e.clientY;
}

export function useToast(props: ToastProps) {
  const [isRunning, setIsRunning] = useState(true);
  const [preventExitTransition, setPreventExitTransition] = useState(false);
  const toastRef = useRef<HTMLDivElement>(null);
  const drag = useKeeper<Draggable>({
    start: 0,
    x: 0,
    y: 0,
    delta: 0,
    removalDistance: 0,
    canCloseOnClick: true,
    canDrag: false,
    boundingRect: null
  });
  const syncProps = useKeeper(props, true);
  const { autoClose, pauseOnHover, closeToast, onClick, closeOnClick } = props;

  useEffect(() => {
    if (isFn(props.onOpen))
      props.onOpen(isValidElement(props.children) && props.children.props);

    return () => {
      if (isFn(syncProps.onClose))
        syncProps.onClose(
          isValidElement(syncProps.children) && syncProps.children.props
        );
    };
  }, []);

  useEffect(() => {
    props.draggable && bindDragEvents();
    return () => {
      props.draggable && unbindDragEvents();
    };
  }, [props.draggable]);

  useEffect(() => {
    props.pauseOnFocusLoss && bindFocusEvents();
    return () => {
      props.pauseOnFocusLoss && unbindFocusEvents();
    };
  }, [props.pauseOnFocusLoss]);

  function onDragStart(
    e: React.MouseEvent<HTMLElement, MouseEvent> | React.TouchEvent<HTMLElement>
  ) {
    if (props.draggable) {
      const toast = toastRef.current!;
      drag.canCloseOnClick = true;
      drag.canDrag = true;
      drag.boundingRect = toast.getBoundingClientRect();
      toast.style.transition = '';
      drag.x = getX(e.nativeEvent as DragEvent);
      drag.y = getY(e.nativeEvent as DragEvent);

      if (props.draggableDirection === Direction.X) {
        drag.start = drag.x;
        drag.removalDistance =
          toast.offsetWidth * (props.draggablePercent / 100);
      } else {
        drag.start = drag.y;
        drag.removalDistance =
          toast.offsetHeight * (props.draggablePercent / 100);
      }
    }
  }

  function onDragTransitionEnd() {
    if (drag.boundingRect) {
      const { top, bottom, left, right } = drag.boundingRect;
{'fraction_non_alphanumeric': 0.13458501491489736, 'fraction_numerical': 0.005790489559571854, 'mean_word_length': 3.1184971098265897, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2933513', 'n_tokens_mistral': 1915, 'n_tokens_neox': 1871, 'n_words': 372}