|
| 1 | +/** |
| 2 | + * Copyright IBM Corp. 2021, 2025 |
| 3 | + * |
| 4 | + * This source code is licensed under the Apache-2.0 license found in the |
| 5 | + * LICENSE file in the root directory of this source tree. |
| 6 | + */ |
| 7 | + |
| 8 | +import React, { type ComponentType, type ReactNode } from 'react'; |
| 9 | +import { WarningAltFilled, WarningFilled } from '@carbon/icons-react'; |
| 10 | +import { Text } from '../components/Text'; |
| 11 | +import { usePrefix } from './usePrefix'; |
| 12 | + |
| 13 | +interface InputProps { |
| 14 | + /** The ID for the input. */ |
| 15 | + id: string; |
| 16 | + /** Whether the input is read-only. */ |
| 17 | + readOnly?: boolean; |
| 18 | + /** Whether the input is disabled. */ |
| 19 | + disabled: boolean; |
| 20 | + /** Whether the input is an invalid state. */ |
| 21 | + invalid: boolean; |
| 22 | + /** The message displayed when the input is invalid. */ |
| 23 | + invalidText?: ReactNode; |
| 24 | + /** Whether the input is in a warning state. */ |
| 25 | + warn: boolean; |
| 26 | + /** The message displayed when the input is in a warning state. */ |
| 27 | + warnText?: ReactNode; |
| 28 | +} |
| 29 | + |
| 30 | +interface NormalizedInputProps { |
| 31 | + /** Disabled state. */ |
| 32 | + disabled: boolean; |
| 33 | + /** Invalid state. */ |
| 34 | + invalid: boolean; |
| 35 | + /** The generated ID for the error message. */ |
| 36 | + invalidId: string; |
| 37 | + /** The generated ID for the helper text. */ |
| 38 | + helperId: string; |
| 39 | + /** Warning state. */ |
| 40 | + warn: boolean; |
| 41 | + /** The generated ID for the warning message. */ |
| 42 | + warnId: string; |
| 43 | + /** A React node containing the validation message. */ |
| 44 | + validation: ReactNode | null; |
| 45 | + /** A React component representing the accompanying icon. */ |
| 46 | + icon: ComponentType | null; |
| 47 | +} |
| 48 | + |
| 49 | +/** |
| 50 | + * Returns an object containing normalized properties for an input component. |
| 51 | + * |
| 52 | + * This hook ensures that only one of `invalid` or `warn` is active (with |
| 53 | + * `invalid` taking precedence) and that `readOnly` overrides the `disabled`, |
| 54 | + * `invalid`, and `warn` states. It generates unique IDs for error, warning, and |
| 55 | + * helper messages, and conditionally provides the appropriate validation |
| 56 | + * message and accompanying icon. |
| 57 | + */ |
| 58 | +export const useNormalizedInputProps = ({ |
| 59 | + id, |
| 60 | + readOnly, |
| 61 | + disabled, |
| 62 | + invalid, |
| 63 | + invalidText, |
| 64 | + warn, |
| 65 | + warnText, |
| 66 | +}: InputProps): NormalizedInputProps => { |
| 67 | + const prefix = usePrefix(); |
| 68 | + const normalizedProps: NormalizedInputProps = { |
| 69 | + disabled: !readOnly && disabled, |
| 70 | + invalid: !readOnly && invalid, |
| 71 | + invalidId: `${id}-error-msg`, |
| 72 | + warn: !readOnly && !invalid && warn, |
| 73 | + warnId: `${id}-warn-msg`, |
| 74 | + validation: null, |
| 75 | + icon: null, |
| 76 | + helperId: `${id}-helper-text`, |
| 77 | + }; |
| 78 | + |
| 79 | + if (normalizedProps.invalid) { |
| 80 | + normalizedProps.icon = WarningFilled; |
| 81 | + normalizedProps.validation = ( |
| 82 | + <Text |
| 83 | + as="div" |
| 84 | + className={`${prefix}--form-requirement`} |
| 85 | + id={normalizedProps.invalidId}> |
| 86 | + {invalidText} |
| 87 | + </Text> |
| 88 | + ); |
| 89 | + } else if (normalizedProps.warn) { |
| 90 | + normalizedProps.icon = WarningAltFilled; |
| 91 | + normalizedProps.validation = ( |
| 92 | + <Text |
| 93 | + as="div" |
| 94 | + className={`${prefix}--form-requirement`} |
| 95 | + id={normalizedProps.warnId}> |
| 96 | + {warnText} |
| 97 | + </Text> |
| 98 | + ); |
| 99 | + } |
| 100 | + |
| 101 | + return normalizedProps; |
| 102 | +}; |
0 commit comments