UNPKG

@kiwicom/orbit-components

Version:

Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com's products.

209 lines (208 loc) 11.7 kB
"use strict"; "use client"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; exports.__esModule = true; exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _Button = _interopRequireDefault(require("../Button")); var _ButtonLink = _interopRequireDefault(require("../ButtonLink")); var _FormLabel = _interopRequireDefault(require("../FormLabel")); var _ErrorFormTooltip = _interopRequireDefault(require("../ErrorFormTooltip")); var _Attachment = _interopRequireDefault(require("../icons/Attachment")); var _CloseCircle = _interopRequireDefault(require("../icons/CloseCircle")); var _getFieldDataState = _interopRequireDefault(require("../common/getFieldDataState")); var _useErrorTooltip = _interopRequireDefault(require("../ErrorFormTooltip/hooks/useErrorTooltip")); var _tailwind = require("../common/tailwind"); /** * @orbit-doc-start * README * ---------- * # InputFile * * To implement InputFile component into your project you'll need to add the import: * * ```jsx * import InputFile from "@kiwicom/orbit-components/lib/InputFile"; * ``` * * After adding import into your project you can use it simply like: * * ```jsx * <InputFile labelRemove="Remove file" /> * ``` * * ## Props * * Table below contains all types of the props available in the InputFile component. * * | Name | Type | Default | Description | * | :--------------- | :------------------------- | :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | * | allowedFileTypes | `string \| string[]` | | You can specify allow file types. [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers) | * | buttonLabel | `Translation` | `"Select file"` | The label for the Button inside InputFile. [See Functional specs](#functional-specs) | * | dataTest | `string` | | Optional prop for testing purposes. | * | id | `string` | | Set `id` for `InputFile` | * | error | `React.Node` | | The error message for the Select. [See Functional specs](#functional-specs) | * | fileName | `string` | | The name of selected file. | * | help | `React.Node` | | The help message for the InputFile. | * | label | `Translation` | | The label for the InputFile. | * | name | `string` | | The name for the InputFile. | * | onBlur | `event => void \| Promise` | | Function for handling onBlur event. | * | onChange | `event => void \| Promise` | | Function for handling onChange event. | * | required | `boolean` | | If true, the label is displayed as required. | * | onFocus | `event => void \| Promise` | | Function for handling onFocus event. | * | onRemoveFile | `() => void \| Promise` | | Function for handling file name removing. | * | placeholder | `TranslationString` | `"No file selected"` | The placeholder for the InputFile. [See Functional specs](#functional-specs) | * | ref | `func` | | Prop for forwarded ref of the InputFile. [See Functional specs](#functional-specs) | * | spaceAfter | `enum` | | Additional `margin-bottom` after component. | * | tabIndex | `string \| number` | | Specifies the tab order of an element | * | width | `string` | `100%` | Specifies width of InputFile | * | insideInputGroup | `boolean` | `false` | Set to `true` if InputFile is inside InputGroup | * | multiple | `boolean` | | If set to `true` will allow to upload multiple files | * | disabled | `boolean` | | If set to `true` will allow to upload multiple files | * | labelRemove | `string` | | Required label for the remove file button. | * * ### enum * * | spaceAfter | * | :----------- | * | `"none"` | * | `"smallest"` | * | `"small"` | * | `"normal"` | * | `"medium"` | * | `"large"` | * | `"largest"` | * * ## Functional specs * * - The `error` prop overwrites the `help` prop, due to higher priority. * * - If you pass some `string` into **placeholder** it will be used as its placeholder. * * - If you pass some `string` into **buttonLabel** it will be used for button content. * * - `ref` can be used for example auto-focus the elements immediately after render. * * * @orbit-doc-end */ const InputFile = props => { const { placeholder = "No file selected", buttonLabel = "Select file", required, onRemoveFile, dataTest, id, spaceAfter, width = "100%", help, error, onFocus, onBlur, name, label, multiple, onChange, disabled = false, allowedFileTypes, tabIndex, fileName, insideInputGroup, labelRemove, ref } = props; const hasTooltip = Boolean(error || help); const { tooltipShown, tooltipShownHover, setTooltipShown, setTooltipShownHover, labelRef, iconRef, handleFocus } = (0, _useErrorTooltip.default)({ onFocus, hasTooltip }); const shown = tooltipShown || tooltipShownHover; const onClick = e => { if (iconRef && iconRef.current && iconRef.current.contains(e.target)) { e.preventDefault(); e.stopPropagation(); } }; return ( /*#__PURE__*/ // Disabling because the onClick exists just to stop propagation of events // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions React.createElement("label", { onClick: onClick, ref: labelRef, className: (0, _clsx.default)("font-base relative block w-full", spaceAfter && _tailwind.spaceAfterClasses[spaceAfter]), style: { width } }, /*#__PURE__*/React.createElement("input", { "data-test": dataTest, id: id, disabled: disabled, "aria-required": required, multiple: multiple, "data-state": insideInputGroup && typeof error === "undefined" ? undefined : (0, _getFieldDataState.default)(!!props.error), type: "file", name: name, onChange: onChange, onFocus: handleFocus, onBlur: onBlur, accept: Array.isArray(allowedFileTypes) ? allowedFileTypes.join(",") : allowedFileTypes, tabIndex: tabIndex ? Number(tabIndex) : undefined, className: "peer pointer-events-none absolute h-0 opacity-0" }), label && /*#__PURE__*/React.createElement(_FormLabel.default, { required: required, error: !!error, help: !!help, labelRef: labelRef, iconRef: iconRef, onMouseEnter: () => setTooltipShownHover(true), onMouseLeave: () => setTooltipShownHover(false) }, label), /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("peer-focus:outline-blue-normal peer-focus:outline peer-focus:outline-2", "box-border flex items-center", "h-form-box-normal ps-150", error ? "shadow-form-element-error" : "shadow-form-element", !disabled && (error ? "hover:shadow-form-element-error-hover" : "hover:shadow-form-element-hover"), "duration-fast transition-shadow ease-in-out", "rounded-200", disabled ? "bg-form-element-disabled-background cursor-not-allowed" : "bg-form-element-background cursor-pointer") }, /*#__PURE__*/React.createElement(_Button.default, { type: "secondary", disabled: disabled, size: "small", iconLeft: /*#__PURE__*/React.createElement(_Attachment.default, { ariaHidden: true }), asComponent: "div", role: "button" }, buttonLabel), /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("font-base ps-300 w-full truncate", error ? "text-red-normal" : "text-ink-normal"), ref: ref }, fileName || placeholder), fileName && /*#__PURE__*/React.createElement(_ButtonLink.default, { type: "primary", disabled: disabled, compact: true, iconLeft: /*#__PURE__*/React.createElement(_CloseCircle.default, { ariaLabel: labelRemove, color: "secondary" }), onClick: ev => { ev.preventDefault(); if (onRemoveFile) { onRemoveFile(); } } })), !insideInputGroup && hasTooltip && /*#__PURE__*/React.createElement(_ErrorFormTooltip.default, { help: help, error: error, referenceElement: labelRef, shown: shown, onShown: setTooltipShown })) ); }; var _default = exports.default = InputFile;