UNPKG

@trail-ui/react

Version:
187 lines (184 loc) 5.02 kB
import { removeDataAttributes, useSlot } from "./chunk-4CU75PXA.mjs"; // src/text-field/text-field.tsx import { clsx } from "@trail-ui/shared-utils"; import { textField } from "@trail-ui/theme"; import { filterDOMProps } from "@react-aria/utils"; import { useControlledState } from "@react-stately/utils"; import { createContext, forwardRef, useCallback, useMemo, useRef, useState } from "react"; import { useTextField } from "react-aria"; import { InputContext, Label, Provider, Text, TextAreaContext, useContextProps } from "react-aria-components"; import { ErrorIcon } from "@trail-ui/icons"; import { jsx, jsxs } from "react/jsx-runtime"; var TextFieldContext = createContext(null); function TextField(props, ref) { [props, ref] = useContextProps(props, ref, TextFieldContext); let inputRef = useRef(null); let [labelRef, label] = useSlot(); let [inputElementType, setInputElementType] = useState("input"); const { onValueChange = () => { }, onClear, className, classNames, children, label: labelValue, description, errorMessage, errorId, errorIcon = /* @__PURE__ */ jsx( ErrorIcon, { className: "h-4 w-4 text-red-800 dark:text-red-600", role: "img", "aria-label": "Error", "aria-hidden": false } ) } = props; const handleValueChange = useCallback( (value) => { onValueChange(value != null ? value : ""); }, [onValueChange] ); const [inputValue, setInputValue] = useControlledState( props.value, props.defaultValue, handleValueChange ); const handleValueClear = useCallback(() => { setInputValue(""); onClear == null ? void 0 : onClear(); }, [onClear, setInputValue]); let { labelProps, inputProps, descriptionProps } = useTextField( { ...removeDataAttributes(props), value: inputValue, inputElementType, label, onChange: setInputValue }, inputRef ); let inputOrTextAreaRef = useCallback((el) => { inputRef.current = el; if (el) { setInputElementType(el instanceof HTMLTextAreaElement ? "textarea" : "input"); } }, []); const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className); const slots = useMemo(() => textField(), []); const hasHelper = !!description || !!errorMessage; const helpComponent = useMemo(() => { if (!hasHelper) return null; return errorMessage ? /* @__PURE__ */ jsxs( Text, { id: errorId, slot: "errorMessage", "aria-live": "polite", elementType: "div", className: `${slots.errorMessage({ class: classNames == null ? void 0 : classNames.errorMessage })}`, children: [ errorIcon, /* @__PURE__ */ jsx("span", { children: errorMessage }) ] } ) : description ? /* @__PURE__ */ jsx( Text, { slot: "description", elementType: "div", className: slots.description({ class: classNames == null ? void 0 : classNames.description }), ...descriptionProps, children: /* @__PURE__ */ jsx("span", { children: description }) } ) : null; }, [ classNames == null ? void 0 : classNames.description, classNames == null ? void 0 : classNames.errorMessage, description, descriptionProps, hasHelper, errorIcon, errorMessage, errorId, slots ]); return /* @__PURE__ */ jsx( "div", { ...filterDOMProps(props), className: slots.base({ class: baseStyles }), ref, slot: props.slot || void 0, "data-disabled": props.isDisabled || void 0, "data-invalid": props.isInvalid || void 0, "data-required": props.isRequired || void 0, "data-readonly": props.isReadOnly || void 0, "data-orientation": props.orientation || "vertical", children: /* @__PURE__ */ jsxs( Provider, { values: [ [ InputContext, { ...inputProps, "data-value": inputValue, onClear: onClear ? handleValueClear : void 0, ref: inputOrTextAreaRef } ], [ TextAreaContext, { ...inputProps, "data-value": inputValue, onClear: onClear ? handleValueClear : void 0, ref: inputOrTextAreaRef } ] ], children: [ labelValue && /* @__PURE__ */ jsx( Label, { ...labelProps, ref: labelRef, className: slots.label({ class: classNames == null ? void 0 : classNames.label }), children: labelValue } ), children, helpComponent ] } ) } ); } var _TextField = forwardRef(TextField); export { TextFieldContext, _TextField };