Files
NapCatQQ/.pnpm-store/v3/files/87/a3a72f5bd042e7b7e83d6511fed927fe5cf83bd0ec984ef3a86608323f3538dd2bf3780dd428896ed67b69d5a58890549d854782148b56c77ccdbdb781f460
T
TanTan e311ca3275
Build NapCat Artifacts / Type Check & Test (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:25:58 +08:00

417 lines
14 KiB
Plaintext

"use client";
// src/use-input.ts
import { mapPropsVariants, useProviderContext } from "@heroui/system";
import { useSafeLayoutEffect } from "@heroui/use-safe-layout-effect";
import { useFocusRing } from "@react-aria/focus";
import { input } from "@heroui/theme";
import { useDOMRef, filterDOMProps } from "@heroui/react-utils";
import { useFocusWithin, useHover, usePress } from "@react-aria/interactions";
import { clsx, dataAttr, isEmpty, objectToDeps, safeAriaLabel } from "@heroui/shared-utils";
import { useControlledState } from "@react-stately/utils";
import { useMemo, useCallback, useState } from "react";
import { chain, mergeProps } from "@react-aria/utils";
import { useTextField } from "@react-aria/textfield";
import { FormContext, useSlottedContext } from "@heroui/form";
function useInput(originalProps) {
var _a, _b, _c, _d;
const globalContext = useProviderContext();
const { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
const [props, variantProps] = mapPropsVariants(originalProps, input.variantKeys);
const {
ref,
as,
type,
label,
baseRef,
wrapperRef,
description,
className,
classNames,
autoFocus,
startContent,
endContent,
onClear,
onChange,
validationState,
validationBehavior = (_a = formValidationBehavior != null ? formValidationBehavior : globalContext == null ? void 0 : globalContext.validationBehavior) != null ? _a : "native",
innerWrapperRef: innerWrapperRefProp,
onValueChange = () => {
},
...otherProps
} = props;
const handleValueChange = useCallback(
(value) => {
onValueChange(value != null ? value : "");
},
[onValueChange]
);
const [isFocusWithin, setFocusWithin] = useState(false);
const Component = as || "div";
const disableAnimation = (_c = (_b = originalProps.disableAnimation) != null ? _b : globalContext == null ? void 0 : globalContext.disableAnimation) != null ? _c : false;
const domRef = useDOMRef(ref);
const baseDomRef = useDOMRef(baseRef);
const inputWrapperRef = useDOMRef(wrapperRef);
const innerWrapperRef = useDOMRef(innerWrapperRefProp);
const [inputValue, setInputValue] = useControlledState(
props.value,
(_d = props.defaultValue) != null ? _d : "",
handleValueChange
);
const isFilledByDefault = ["date", "time", "month", "week", "range"].includes(type);
const isFilled = !isEmpty(inputValue) || isFilledByDefault;
const isFilledWithin = isFilled || isFocusWithin;
const isHiddenType = type === "hidden";
const isMultiline = originalProps.isMultiline;
const isFileTypeInput = type === "file";
const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className, isFilled ? "is-filled" : "");
const handleClear = useCallback(() => {
var _a2;
setInputValue("");
onClear == null ? void 0 : onClear();
(_a2 = domRef.current) == null ? void 0 : _a2.focus();
}, [setInputValue, onClear]);
useSafeLayoutEffect(() => {
if (!domRef.current)
return;
setInputValue(domRef.current.value);
}, [domRef.current]);
const {
labelProps,
inputProps,
isInvalid: isAriaInvalid,
validationErrors,
validationDetails,
descriptionProps,
errorMessageProps
} = useTextField(
{
...originalProps,
validationBehavior,
autoCapitalize: originalProps.autoCapitalize,
value: inputValue,
"aria-label": safeAriaLabel(
originalProps["aria-label"],
originalProps.label,
originalProps.placeholder
),
inputElementType: isMultiline ? "textarea" : "input",
onChange: setInputValue
},
domRef
);
if (isFileTypeInput) {
delete inputProps.value;
delete inputProps.onChange;
}
const { isFocusVisible, isFocused, focusProps } = useFocusRing({
autoFocus,
isTextInput: true
});
const { isHovered, hoverProps } = useHover({ isDisabled: !!(originalProps == null ? void 0 : originalProps.isDisabled) });
const { isHovered: isLabelHovered, hoverProps: labelHoverProps } = useHover({
isDisabled: !!(originalProps == null ? void 0 : originalProps.isDisabled)
});
const { focusProps: clearFocusProps, isFocusVisible: isClearButtonFocusVisible } = useFocusRing();
const { focusWithinProps } = useFocusWithin({
onFocusWithinChange: setFocusWithin
});
const { pressProps: clearPressProps } = usePress({
isDisabled: !!(originalProps == null ? void 0 : originalProps.isDisabled) || !!(originalProps == null ? void 0 : originalProps.isReadOnly),
onPress: handleClear
});
const isInvalid = validationState === "invalid" || isAriaInvalid;
const labelPlacement = useMemo(() => {
var _a2;
if ((!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && !label) {
return "outside";
}
return (_a2 = originalProps.labelPlacement) != null ? _a2 : "inside";
}, [originalProps.labelPlacement, label]);
const errorMessage = typeof props.errorMessage === "function" ? props.errorMessage({ isInvalid, validationErrors, validationDetails }) : props.errorMessage || (validationErrors == null ? void 0 : validationErrors.join(" "));
const isClearable = !!onClear || originalProps.isClearable;
const hasElements = !!label || !!description || !!errorMessage;
const hasPlaceholder = !!props.placeholder;
const hasLabel = !!label;
const hasHelper = !!description || !!errorMessage;
const shouldLabelBeOutside = labelPlacement === "outside" || labelPlacement === "outside-left";
const shouldLabelBeInside = labelPlacement === "inside";
const isPlaceholderShown = domRef.current ? (!domRef.current.value || domRef.current.value === "" || !inputValue || inputValue === "") && hasPlaceholder : false;
const isOutsideLeft = labelPlacement === "outside-left";
const hasStartContent = !!startContent;
const isLabelOutside = shouldLabelBeOutside ? labelPlacement === "outside-left" || hasPlaceholder || labelPlacement === "outside" && hasStartContent : false;
const isLabelOutsideAsPlaceholder = labelPlacement === "outside" && !hasPlaceholder && !hasStartContent;
const slots = useMemo(
() => input({
...variantProps,
isInvalid,
labelPlacement,
isClearable,
disableAnimation
}),
[
objectToDeps(variantProps),
isInvalid,
labelPlacement,
isClearable,
hasStartContent,
disableAnimation
]
);
const getBaseProps = useCallback(
(props2 = {}) => {
return {
ref: baseDomRef,
className: slots.base({ class: baseStyles }),
"data-slot": "base",
"data-filled": dataAttr(
isFilled || hasPlaceholder || hasStartContent || isPlaceholderShown || isFileTypeInput
),
"data-filled-within": dataAttr(
isFilledWithin || hasPlaceholder || hasStartContent || isPlaceholderShown || isFileTypeInput
),
"data-focus-within": dataAttr(isFocusWithin),
"data-focus-visible": dataAttr(isFocusVisible),
"data-readonly": dataAttr(originalProps.isReadOnly),
"data-focus": dataAttr(isFocused),
"data-hover": dataAttr(isHovered || isLabelHovered),
"data-required": dataAttr(originalProps.isRequired),
"data-invalid": dataAttr(isInvalid),
"data-disabled": dataAttr(originalProps.isDisabled),
"data-has-elements": dataAttr(hasElements),
"data-has-helper": dataAttr(hasHelper),
"data-has-label": dataAttr(hasLabel),
"data-has-value": dataAttr(!isPlaceholderShown),
"data-hidden": dataAttr(isHiddenType),
...focusWithinProps,
...props2
};
},
[
slots,
baseStyles,
isFilled,
isFocused,
isHovered,
isLabelHovered,
isInvalid,
hasHelper,
hasLabel,
hasElements,
isPlaceholderShown,
hasStartContent,
isFocusWithin,
isFocusVisible,
isFilledWithin,
hasPlaceholder,
focusWithinProps,
isHiddenType,
originalProps.isReadOnly,
originalProps.isRequired,
originalProps.isDisabled
]
);
const getLabelProps = useCallback(
(props2 = {}) => {
return {
"data-slot": "label",
className: slots.label({ class: classNames == null ? void 0 : classNames.label }),
...mergeProps(labelProps, labelHoverProps, props2)
};
},
[slots, isLabelHovered, labelProps, classNames == null ? void 0 : classNames.label]
);
const getInputProps = useCallback(
(props2 = {}) => {
return {
"data-slot": "input",
"data-filled": dataAttr(isFilled),
"data-filled-within": dataAttr(isFilledWithin),
"data-has-start-content": dataAttr(hasStartContent),
"data-has-end-content": dataAttr(!!endContent),
className: slots.input({
class: clsx(classNames == null ? void 0 : classNames.input, isFilled ? "is-filled" : "", isMultiline ? "pe-0" : "")
}),
...mergeProps(
focusProps,
inputProps,
filterDOMProps(otherProps, {
enabled: true,
labelable: true,
omitEventNames: new Set(Object.keys(inputProps))
}),
props2
),
"aria-readonly": dataAttr(originalProps.isReadOnly),
onChange: chain(inputProps.onChange, onChange),
ref: domRef
};
},
[
slots,
inputValue,
focusProps,
inputProps,
otherProps,
isFilled,
isFilledWithin,
hasStartContent,
endContent,
classNames == null ? void 0 : classNames.input,
originalProps.isReadOnly,
originalProps.isRequired,
onChange
]
);
const getInputWrapperProps = useCallback(
(props2 = {}) => {
return {
ref: inputWrapperRef,
"data-slot": "input-wrapper",
"data-hover": dataAttr(isHovered || isLabelHovered),
"data-focus-visible": dataAttr(isFocusVisible),
"data-focus": dataAttr(isFocused),
className: slots.inputWrapper({
class: clsx(classNames == null ? void 0 : classNames.inputWrapper, isFilled ? "is-filled" : "")
}),
...mergeProps(props2, hoverProps),
onClick: (e) => {
if (domRef.current && e.currentTarget === e.target) {
domRef.current.focus();
}
},
style: {
cursor: "text",
...props2.style
}
};
},
[
slots,
isHovered,
isLabelHovered,
isFocusVisible,
isFocused,
inputValue,
classNames == null ? void 0 : classNames.inputWrapper
]
);
const getInnerWrapperProps = useCallback(
(props2 = {}) => {
return {
...props2,
ref: innerWrapperRef,
"data-slot": "inner-wrapper",
onClick: (e) => {
if (domRef.current && e.currentTarget === e.target) {
domRef.current.focus();
}
},
className: slots.innerWrapper({
class: clsx(classNames == null ? void 0 : classNames.innerWrapper, props2 == null ? void 0 : props2.className)
})
};
},
[slots, classNames == null ? void 0 : classNames.innerWrapper]
);
const getMainWrapperProps = useCallback(
(props2 = {}) => {
return {
...props2,
"data-slot": "main-wrapper",
className: slots.mainWrapper({
class: clsx(classNames == null ? void 0 : classNames.mainWrapper, props2 == null ? void 0 : props2.className)
})
};
},
[slots, classNames == null ? void 0 : classNames.mainWrapper]
);
const getHelperWrapperProps = useCallback(
(props2 = {}) => {
return {
...props2,
"data-slot": "helper-wrapper",
className: slots.helperWrapper({
class: clsx(classNames == null ? void 0 : classNames.helperWrapper, props2 == null ? void 0 : props2.className)
})
};
},
[slots, classNames == null ? void 0 : classNames.helperWrapper]
);
const getDescriptionProps = useCallback(
(props2 = {}) => {
return {
...props2,
...descriptionProps,
"data-slot": "description",
className: slots.description({ class: clsx(classNames == null ? void 0 : classNames.description, props2 == null ? void 0 : props2.className) })
};
},
[slots, classNames == null ? void 0 : classNames.description]
);
const getErrorMessageProps = useCallback(
(props2 = {}) => {
return {
...props2,
...errorMessageProps,
"data-slot": "error-message",
className: slots.errorMessage({ class: clsx(classNames == null ? void 0 : classNames.errorMessage, props2 == null ? void 0 : props2.className) })
};
},
[slots, errorMessageProps, classNames == null ? void 0 : classNames.errorMessage]
);
const getClearButtonProps = useCallback(
(props2 = {}) => {
return {
...props2,
type: "button",
tabIndex: -1,
disabled: originalProps.isDisabled,
"aria-label": "clear input",
"data-slot": "clear-button",
"data-focus-visible": dataAttr(isClearButtonFocusVisible),
className: slots.clearButton({
class: clsx(classNames == null ? void 0 : classNames.clearButton, props2 == null ? void 0 : props2.className)
}),
...mergeProps(clearPressProps, clearFocusProps)
};
},
[slots, isClearButtonFocusVisible, clearPressProps, clearFocusProps, classNames == null ? void 0 : classNames.clearButton]
);
return {
Component,
classNames,
domRef,
label,
description,
startContent,
endContent,
labelPlacement,
isClearable,
hasHelper,
hasStartContent,
isLabelOutside,
isOutsideLeft,
isLabelOutsideAsPlaceholder,
shouldLabelBeOutside,
shouldLabelBeInside,
hasPlaceholder,
isInvalid,
errorMessage,
getBaseProps,
getLabelProps,
getInputProps,
getMainWrapperProps,
getInputWrapperProps,
getInnerWrapperProps,
getHelperWrapperProps,
getDescriptionProps,
getErrorMessageProps,
getClearButtonProps
};
}
export {
useInput
};