{"version":3,"file":"DropZone.cjs","sources":["../../../src/components/DropZone/DropZone.tsx"],"sourcesContent":["'use client'\n\nimport {\n  type ChangeEvent,\n  type ComponentPropsWithRef,\n  type ComponentPropsWithoutRef,\n  type DragEvent,\n  type PropsWithChildren,\n  forwardRef,\n  memo,\n  useCallback,\n  useImperativeHandle,\n  useMemo,\n  useRef,\n  useState,\n} from 'react'\nimport { tv } from 'tailwind-variants'\n\nimport { useIntl } from '../../intl'\nimport { Button } from '../Button'\nimport { FaFolderOpenIcon } from '../Icon'\nimport { VisuallyHiddenText } from '../VisuallyHiddenText'\n\nconst classNameGenerator = tv({\n  slots: {\n    wrapper: [\n      'smarthr-ui-DropZone',\n      'shr-relative',\n      'shr-border-shorthand shr-flex shr-flex-col shr-items-center shr-justify-center shr-bg-column shr-p-2.5',\n    ],\n    button: '',\n  },\n  variants: {\n    filesDraggedOver: {\n      true: {\n        wrapper: 'shr-border-main',\n      },\n      false: {\n        wrapper: 'shr-border-dashed',\n      },\n    },\n    disabled: {\n      true: {\n        wrapper: 'shr-cursor-not-allowed',\n      },\n    },\n    error: {\n      true: {\n        button: 'shr-border-danger',\n      },\n    },\n  },\n})\n\ntype AbstractProps = PropsWithChildren<{\n  /**\n   * ボタンまたはドラッグ&ドロップでファイルが追加された時に発火するコールバック関数\n   */\n  onSelectFiles: (\n    e: DragEvent<HTMLElement> | ChangeEvent<HTMLInputElement>,\n    files: FileList | null,\n  ) => void\n  /**\n   * 許可するファイル型を表す1つ以上の固有ファイル型指定子\n   * <b>（ドラッグ&ドロップの挙動には影響しません）</b>\n   */\n  accept?: string\n  /** 複数ファイルを選択できるかどうか */\n  multiple?: boolean\n  name?: string\n  disabled?: boolean\n  /** フォームにエラーがあるかどうか */\n  error?: boolean\n  /** ファイル選択ボタンのラベル */\n  selectButtonLabel?: string\n}>\ntype Props = AbstractProps & Omit<ComponentPropsWithRef<'div'>, keyof AbstractProps>\n\nconst overrideEventDefault = (e: DragEvent<HTMLElement>) => {\n  e.preventDefault()\n  e.stopPropagation()\n}\n\nexport const DropZone = forwardRef<HTMLInputElement, Props>(\n  (\n    { children, onSelectFiles, multiple = true, disabled, error, selectButtonLabel, ...rest },\n    ref,\n  ) => {\n    const fileRef = useRef<HTMLInputElement>(null)\n    const [filesDraggedOver, setFilesDraggedOver] = useState(false)\n    const classNames = useMemo(() => {\n      const { wrapper, button } = classNameGenerator({ filesDraggedOver, disabled, error })\n      return {\n        wrapper: wrapper(),\n        button: button(),\n      }\n    }, [disabled, error, filesDraggedOver])\n    useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>(\n      ref,\n      () => fileRef.current,\n    )\n\n    const onDrop = useCallback(\n      (e: DragEvent<HTMLElement>) => {\n        overrideEventDefault(e)\n        setFilesDraggedOver(false)\n        onSelectFiles(e, e.dataTransfer.files)\n\n        if (fileRef.current) {\n          fileRef.current.files = e.dataTransfer.files\n        }\n      },\n      [setFilesDraggedOver, onSelectFiles],\n    )\n\n    const onDragOver = useCallback(\n      (e: DragEvent<HTMLElement>) => {\n        overrideEventDefault(e)\n        setFilesDraggedOver(true)\n      },\n      [setFilesDraggedOver],\n    )\n\n    const onDragLeave = useCallback(() => {\n      setFilesDraggedOver(false)\n    }, [setFilesDraggedOver])\n\n    const onChange = useCallback(\n      (e: ChangeEvent<HTMLInputElement>) => {\n        onSelectFiles(e, e.target.files)\n      },\n      [onSelectFiles],\n    )\n\n    const onClickButton = useCallback(() => {\n      fileRef.current!.click()\n    }, [])\n\n    return (\n      // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n      <div\n        onDrop={onDrop}\n        onDragOver={onDragOver}\n        onDragLeave={onDragLeave}\n        className={classNames.wrapper}\n      >\n        {children}\n        <SelectButton\n          onClick={onClickButton}\n          disabled={disabled}\n          className={classNames.button}\n          label={selectButtonLabel}\n        />\n        <VisuallyHiddenText>\n          {/* eslint-disable-next-line smarthr/a11y-input-in-form-control */}\n          <input\n            {...rest}\n            data-smarthr-ui-input=\"true\"\n            ref={fileRef}\n            type=\"file\"\n            multiple={multiple}\n            disabled={disabled}\n            tabIndex={-1}\n            aria-invalid={error || undefined}\n            onChange={onChange}\n          />\n        </VisuallyHiddenText>\n      </div>\n    )\n  },\n)\n\nconst SelectButton = memo<\n  ComponentPropsWithoutRef<typeof Button> & { onClick: () => void; label?: string }\n>(({ onClick, label, ...rest }) => {\n  const { localize } = useIntl()\n\n  const buttonLabel = useMemo(\n    () =>\n      label ||\n      localize({\n        id: 'smarthr-ui/DropZone/selectButtonLabel',\n        defaultText: 'ファイルを選択',\n      }),\n    [label, localize],\n  )\n\n  return (\n    <Button {...rest} prefix={<FaFolderOpenIcon />} onClick={onClick}>\n      {buttonLabel}\n    </Button>\n  )\n})\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAuBA;AACE;AACE;;;;AAIC;AACD;AACD;AACD;AACE;AACE;AACE;AACD;AACD;AACE;AACD;AACF;AACD;AACE;AACE;AACD;AACF;AACD;AACE;AACE;AACD;AACF;AACF;AACF;AA0BD;;;AAGA;AAEO;AAKH;;AAEA;AACE;;;;;;;AAWF;;;;AAMI;;;AAGF;AAIF;;;AAIE;AAIF;;AAEA;AAEA;;AAGE;AAIF;AACE;;;;AAKA;AA6BJ;AAGF;AAGE;AAEA;AAGI;AACE;AACA;AACD;AAIL;AAKF;;"}