UNPKG

@nex-ui/react

Version:

🎉 A beautiful, modern, and reliable React component library.

235 lines (231 loc) • 7.77 kB
"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;