@trail-ui/react
Version:
187 lines (184 loc) • 5.02 kB
JavaScript
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
};