UNPKG

@intility/bifrost-react

Version:

React library for Intility's design system, Bifrost.

158 lines (157 loc) 6.85 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useRef, forwardRef, useEffect, useState } from "react"; import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons/faTriangleExclamation"; import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck"; import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark"; import classNames from "classnames"; import Icon from "../Icon/Icon.js"; import setRef from "../../utils/setRef.js"; import triggerOnChange from "../../utils/triggerOnChange.js"; import bfSpinner from "../../assets/bfSpinner.js"; import useUniqueId from "../../hooks/useUniqueId.js"; import Label from "../Label/Label.js"; import Description from "../Description/Description.js"; import Feedback from "../Feedback/Feedback.js"; /** * Text input field */ const Input = /*#__PURE__*/ forwardRef(({ label, hideLabel = false, icon, iconProps, rightIcon = false, className, style, id, disabled = false, readOnly = false, state = "default", feedback, required = false, description, requiredNoLabel = false, optional = false, clearable = false, loading = false, onIconClick, iconButton, inputClassName, inputStyle, small = false, ...props }, ref)=>{ const inputId = useUniqueId(id); let hasState = !!state && state !== "default"; const iconProp = icon || iconProps?.icon; const inputRef = useRef(null); const handleClear = ()=>{ if (disabled) return; if (inputRef.current) { triggerOnChange(inputRef.current, ""); inputRef.current.focus(); } }; const isControlled = "value" in props; const [uncontrolledHasClearableValue, setUncontrolledHasClearableValue] = useState(!!props.defaultValue); // detect uncontrolled value for clearable inputs useEffect(()=>{ const inputElement = inputRef.current; // only detect if clearable and uncontrolled if (!inputElement || !clearable || isControlled) return; const uncontrolledInputHandler = ()=>{ setUncontrolledHasClearableValue(!!inputElement.value); }; inputElement.addEventListener("input", uncontrolledInputHandler); return ()=>{ inputElement.removeEventListener("input", uncontrolledInputHandler); }; }, [ isControlled, clearable ]); const showClearButton = clearable && (isControlled ? !!props.value : uncontrolledHasClearableValue); let inputIcon = null; if (iconProp && !(hasState && rightIcon)) { inputIcon = /*#__PURE__*/ _jsx(Icon, { icon: loading ? bfSpinner : iconProp, spin: loading, "data-testid": "bf-input-icon", ...iconProps, className: classNames(iconProps?.className, { "bf-input-loading-icon": loading }) }); inputIcon = onIconClick ? /*#__PURE__*/ _jsx("button", { type: "button", className: "bf-input-icon bf-input-icon-button", onClick: onIconClick, disabled: disabled, children: inputIcon }) : /*#__PURE__*/ _jsx("span", { className: classNames(iconProps?.className, "bf-input-icon"), children: inputIcon }); } else if (loading) { inputIcon = /*#__PURE__*/ _jsx("span", { className: "bf-input-icon", children: /*#__PURE__*/ _jsx(Icon, { icon: bfSpinner, spin: true, className: "bf-input-loading-icon" }) }); rightIcon = true; hasState = false; } return /*#__PURE__*/ _jsxs("div", { className: classNames(className, "bf-input-container", { "bf-input-disabled": disabled, "bf-input-success": state === "success", "bf-input-warning": state === "warning", "bf-input-alert": state === "alert", "bf-input-small": small }), style: style, "data-testid": "bf-input-container", children: [ !hideLabel && /*#__PURE__*/ _jsx(Label, { htmlFor: inputId, required: !disabled && required && !requiredNoLabel, optional: optional, disabled: disabled, readOnly: readOnly, children: label }), /*#__PURE__*/ _jsx(Description, { children: description }), /*#__PURE__*/ _jsxs("div", { className: classNames("bf-input-icon-container", { "bf-input-icon-right": !hasState && inputIcon && rightIcon, "bf-input-icon-left": inputIcon && !rightIcon, "bf-input-icon-state": hasState, "bf-input-clearable": showClearButton, "bf-input-icon-button-filled": iconButton }), "data-testid": "bf-input-icon-container", children: [ /*#__PURE__*/ _jsx("input", { id: inputId, disabled: disabled, readOnly: readOnly, required: !disabled && (required || requiredNoLabel), ...hideLabel && typeof label === "string" && { "aria-label": label }, autoComplete: "off", ...props, style: inputStyle, ref: (r)=>{ setRef(ref, r); setRef(inputRef, r); }, className: classNames("bf-input", inputClassName, { "bf-input-state-only": hasState && !inputIcon }) }), inputIcon, showClearButton && /*#__PURE__*/ _jsx("span", { className: "bf-input-clear-icon", onClick: ()=>handleClear(), "data-testid": "bf-input-clear-icon", children: /*#__PURE__*/ _jsx(Icon, { icon: faXmark }) }), hasState && /*#__PURE__*/ _jsx("span", { className: "bf-state-icon", children: /*#__PURE__*/ _jsx(Icon, { icon: state === "alert" || state === "warning" ? faTriangleExclamation : faCheck }) }) ] }), /*#__PURE__*/ _jsx(Feedback, { children: feedback }) ] }); }); Input.displayName = "Input"; export default Input;