@nex-ui/react
Version:
🎉 A beautiful, modern, and reliable React component library.
235 lines (231 loc) • 7.77 kB
JavaScript
"use client";
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
var utils = require('@nex-ui/utils');
var hooks = require('@nex-ui/hooks');
var icons = require('@nex-ui/icons');
var Context = require('../provider/Context.cjs');
var useDefaultProps = require('../utils/useDefaultProps.cjs');
var useStyles = require('../utils/useStyles.cjs');
var useSlotClasses = require('../utils/useSlotClasses.cjs');
var useSlot = require('../utils/useSlot.cjs');
var InputBase = require('../inputBase/InputBase.cjs');
var ButtonBase = require('../buttonBase/ButtonBase.cjs');
var input = require('../../theme/recipes/input.cjs');
const slots = [
'root',
'input',
'clearButton',
'suffix',
'prefix',
'label'
];
const useSlotAriaProps = (ownerState)=>{
const { label, slotProps, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, id: idProp } = ownerState;
const id = react.useId();
return react.useMemo(()=>{
const hasLabel = !!label;
const stringLabel = utils.isString(label);
const labelProps = slotProps?.label ?? {};
const clearButtonProps = slotProps?.clearButton ?? {};
const inputId = idProp ?? (hasLabel ? `input-${id}` : undefined);
const labelId = labelProps['id'] ?? (hasLabel ? `label-${id}` : undefined);
return {
input: {
id: inputId,
'aria-labelledby': ariaLabelledBy ?? labelId,
'aria-label': ariaLabel ?? (stringLabel ? label : undefined)
},
label: {
id: labelId,
htmlFor: inputId
},
clearButton: {
'aria-label': clearButtonProps['aria-label'] ?? 'Clear input',
tabIndex: -1
}
};
}, [
ariaLabel,
ariaLabelledBy,
id,
idProp,
label,
slotProps?.clearButton,
slotProps?.label
]);
};
const Input = (inProps)=>{
const { primaryThemeColor } = Context.useNexUI();
const props = useDefaultProps.useDefaultProps({
name: 'Input',
props: inProps
});
const { sx, label, className, prefix, suffix, onClear, slotProps, onValueChange, placeholder, classNames, defaultValue = '', as = 'input', value: valueProp, color = primaryThemeColor, type = 'text', disabled = false, variant = 'outlined', fullWidth = false, invalid = false, size = 'md', radius = size, clearable = false, labelPlacement: labelPlacementProp = 'float-outside', ...remainingProps } = props;
const [value, setValue] = hooks.useControlledState(valueProp, defaultValue, onValueChange);
const inputRef = react.useRef(null);
const hasLabel = !!label;
const hasValue = !!value;
const hasPlaceholder = !!placeholder;
const hasPrefix = !!prefix;
let labelPlacement = labelPlacementProp;
const floatLabel = labelPlacement === 'float-outside' || labelPlacement === 'float-inside';
const hasDefaultPlaceholder = [
'date',
'datetime-local',
'time',
'week',
'month',
'range'
].includes(type);
if (!hasLabel) {
labelPlacement = undefined;
} else if (floatLabel && (hasPlaceholder || hasValue || hasDefaultPlaceholder || hasPrefix)) {
if (labelPlacementProp === 'float-outside') {
labelPlacement = 'outside';
} else if (labelPlacementProp === 'float-inside') {
labelPlacement = 'inside';
}
}
const ownerState = {
...props,
color,
disabled,
variant,
fullWidth,
size,
radius,
invalid,
type,
clearable,
value,
labelPlacement,
as
};
const styles = useStyles.useStyles({
ownerState,
name: 'Input',
recipe: input.inputRecipe
});
const slotClasses = useSlotClasses.useSlotClasses({
name: 'Input',
slots,
classNames
});
const slotAriaProps = useSlotAriaProps(ownerState);
const handleClearValue = hooks.useEvent(()=>{
setValue('');
onClear?.();
inputRef.current?.focus();
});
const handleChange = hooks.useEvent((e)=>{
setValue(e.target.value);
});
const handleFocusInput = hooks.useEvent((e)=>{
if (inputRef.current && e.target === e.currentTarget) {
inputRef.current.focus();
e.preventDefault();
}
});
const [InputRoot, getInputRootProps] = useSlot.useSlot({
elementType: 'div',
externalSlotProps: slotProps?.root,
style: styles.root,
classNames: slotClasses.root,
additionalProps: {
sx,
className,
onMouseDown: handleFocusInput
},
dataAttrs: {
color,
disabled,
variant,
fullWidth,
size,
radius,
invalid,
clearable,
labelPlacement
}
});
const [InputLabel, getInputLabelProps] = useSlot.useSlot({
elementType: 'label',
externalSlotProps: slotProps?.label,
style: styles.label,
classNames: slotClasses.label,
a11y: slotAriaProps.label
});
const [InputControl, getInputControlProps] = useSlot.useSlot({
elementType: InputBase.InputBase,
externalForwardedProps: remainingProps,
style: styles.input,
classNames: slotClasses.input,
a11y: slotAriaProps.input,
shouldForwardComponent: false,
additionalProps: {
as,
disabled,
invalid,
type,
value,
placeholder,
ref: inputRef,
onChange: handleChange
}
});
const [InputClearButton, getClearButtonProps] = useSlot.useSlot({
elementType: ButtonBase.ButtonBase,
style: styles.clearButton,
externalSlotProps: slotProps?.clearButton,
classNames: slotClasses.clearButton,
a11y: slotAriaProps.clearButton,
shouldForwardComponent: false,
additionalProps: {
onClick: handleClearValue,
disabled: disabled,
sx: {
visibility: value ? 'visible' : 'hidden'
}
}
});
const [InputPrefix, getInputPrefixProps] = useSlot.useSlot({
elementType: 'span',
externalSlotProps: slotProps?.prefix,
style: styles.prefix,
classNames: slotClasses.prefix
});
const [InputSuffix, getInputSuffixProps] = useSlot.useSlot({
elementType: 'span',
externalSlotProps: slotProps?.suffix,
style: styles.suffix,
classNames: slotClasses.suffix
});
return /*#__PURE__*/ jsxRuntime.jsxs(InputRoot, {
...getInputRootProps(),
children: [
label && /*#__PURE__*/ jsxRuntime.jsx(InputLabel, {
...getInputLabelProps(),
children: label
}),
prefix && /*#__PURE__*/ jsxRuntime.jsx(InputPrefix, {
...getInputPrefixProps(),
children: prefix
}),
/*#__PURE__*/ jsxRuntime.jsx(InputControl, {
...getInputControlProps()
}),
clearable && /*#__PURE__*/ jsxRuntime.jsx(InputClearButton, {
...getClearButtonProps(),
children: /*#__PURE__*/ jsxRuntime.jsx(icons.CloseCircleFilled, {})
}),
suffix && /*#__PURE__*/ jsxRuntime.jsx(InputSuffix, {
...getInputSuffixProps(),
children: suffix
})
]
});
};
Input.displayName = 'Input';
exports.Input = Input;