diff --git a/slash/react/src/Form/Checkbox/CheckboxInput.tsx b/slash/react/src/Form/Checkbox/CheckboxInput.tsx index 44f69dfee..0686ed558 100644 --- a/slash/react/src/Form/Checkbox/CheckboxInput.tsx +++ b/slash/react/src/Form/Checkbox/CheckboxInput.tsx @@ -1,11 +1,11 @@ import { ComponentProps, forwardRef } from "react"; -import { Field, useOptionsWithId } from "../core"; +import { LegacyField, useOptionsWithId } from "../core"; import { Checkbox } from "./Checkbox"; import { CheckboxModes } from "./CheckboxModes"; type Props = Omit< - ComponentProps & ComponentProps, + ComponentProps & ComponentProps, "children" | "placeholder" >; @@ -38,7 +38,7 @@ const CheckboxInput = forwardRef( const newOptions = useOptionsWithId(options); return ( - ( ref={inputRef} {...checkboxProps} /> - + ); }, ); diff --git a/slash/react/src/Form/Choice/ChoiceInput.tsx b/slash/react/src/Form/Choice/ChoiceInput.tsx index 0ce09d924..598ea8825 100644 --- a/slash/react/src/Form/Choice/ChoiceInput.tsx +++ b/slash/react/src/Form/Choice/ChoiceInput.tsx @@ -1,9 +1,9 @@ import { forwardRef, type ComponentProps } from "react"; -import { Field, useInputClassModifier, useOptionsWithId } from "../core"; +import { LegacyField, useInputClassModifier, useOptionsWithId } from "../core"; import { Choice } from "./Choice"; type Props = ComponentProps & - Omit, "children">; + Omit, "children">; const defaultOptions = [ { label: "Oui", value: true, id: "radioItemTrue" }, @@ -49,7 +49,7 @@ const ChoiceInput = forwardRef( value: o.value === "true", })); return ( - ( required={required} disabled={disabled} /> - + ); }, ); diff --git a/slash/react/src/Form/Date/DateInput.tsx b/slash/react/src/Form/Date/DateInput.tsx index 3b4fc9411..529633f63 100644 --- a/slash/react/src/Form/Date/DateInput.tsx +++ b/slash/react/src/Form/Date/DateInput.tsx @@ -1,9 +1,14 @@ import { ComponentPropsWithoutRef, ReactNode, useId } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { Date } from "./Date"; type Props = Omit, "placeholderText"> & - ComponentPropsWithoutRef & { + ComponentPropsWithoutRef & { placeholder?: string; helpMessage?: ReactNode; children?: ReactNode; @@ -35,7 +40,7 @@ const DateInput = ({ required, ); return ( - - + ); }; diff --git a/slash/react/src/Form/File/FileInput.tsx b/slash/react/src/Form/File/FileInput.tsx index f77a51db5..19c64f435 100644 --- a/slash/react/src/Form/File/FileInput.tsx +++ b/slash/react/src/Form/File/FileInput.tsx @@ -1,10 +1,15 @@ import "@axa-fr/design-system-slash-css/dist/Form/File/File.scss"; import { ComponentPropsWithoutRef, ReactNode, useId } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { CustomFile, File } from "./File"; import { FileTable } from "./FileTable"; -type FieldProps = ComponentPropsWithoutRef; +type FieldProps = ComponentPropsWithoutRef; type FileProps = ComponentPropsWithoutRef; type FileTableProps = ComponentPropsWithoutRef; @@ -56,7 +61,7 @@ const FileInput = ({ ); const rowModifier = `${inputFieldClassModifier} label-top`; return ( - onDeleteClick(selectedId, inputId)} classModifier={classModifier} /> - + ); }; diff --git a/slash/react/src/Form/MultiSelect/MultiSelectInput.tsx b/slash/react/src/Form/MultiSelect/MultiSelectInput.tsx index a4267e6a4..c8fa468a1 100644 --- a/slash/react/src/Form/MultiSelect/MultiSelectInput.tsx +++ b/slash/react/src/Form/MultiSelect/MultiSelectInput.tsx @@ -1,10 +1,15 @@ import "@axa-fr/design-system-slash-css/dist/Form/MultiSelect/MultiSelect.scss"; import { useId, type ComponentProps, type ReactNode } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { MultiSelect } from "./MultiSelect"; -type Props = ComponentProps & +type Props = ComponentProps & ComponentProps & { helpMessage?: ReactNode; }; @@ -37,7 +42,7 @@ const MultiSelectInput = ({ const inputId = id || generatedId; return ( - - + ); }; diff --git a/slash/react/src/Form/Number/NumberInput.tsx b/slash/react/src/Form/Number/NumberInput.tsx index c0d31fb7e..bf876e868 100644 --- a/slash/react/src/Form/Number/NumberInput.tsx +++ b/slash/react/src/Form/Number/NumberInput.tsx @@ -7,11 +7,16 @@ import { ReactNode, useId, } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { Number } from "./Number"; -type Props = ComponentPropsWithoutRef & +type Props = ComponentPropsWithoutRef & ComponentPropsWithRef & { helpMessage?: ReactNode; children?: ReactNode; @@ -43,7 +48,7 @@ export const NumberInput = ({ required, ); return ( - - + ); }; diff --git a/slash/react/src/Form/Pass/PassInput.tsx b/slash/react/src/Form/Pass/PassInput.tsx index f34a20a23..1246a492a 100644 --- a/slash/react/src/Form/Pass/PassInput.tsx +++ b/slash/react/src/Form/Pass/PassInput.tsx @@ -1,5 +1,10 @@ import { ComponentProps, ReactNode, useId, useState } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { Pass } from "./Pass"; const strengthList: Record = { @@ -25,7 +30,7 @@ const calculateStrength = (score?: string | null) => { }; type PassProps = ComponentProps; -type Props = ComponentProps & +type Props = ComponentProps & Omit & { helpMessage?: ReactNode; score?: string; @@ -63,7 +68,7 @@ const PassInput = ({ ); return ( - - + ); }; diff --git a/slash/react/src/Form/Radio/RadioInput.tsx b/slash/react/src/Form/Radio/RadioInput.tsx index 9e87064e6..e62eceac8 100644 --- a/slash/react/src/Form/Radio/RadioInput.tsx +++ b/slash/react/src/Form/Radio/RadioInput.tsx @@ -1,13 +1,13 @@ import { ComponentPropsWithoutRef, forwardRef } from "react"; import { - Field, + LegacyField, getFirstId, useInputClassModifier, useOptionsWithId, } from "../core"; import { Radio, RadioModes } from "./Radio"; -type RadioInputProps = ComponentPropsWithoutRef & +type RadioInputProps = ComponentPropsWithoutRef & ComponentPropsWithoutRef; const RadioInput = forwardRef( @@ -47,7 +47,7 @@ const RadioInput = forwardRef( ); return ( - ( {...radioProps} /> {children} - + ); }, ); diff --git a/slash/react/src/Form/Select/SelectInput.tsx b/slash/react/src/Form/Select/SelectInput.tsx index 73b64aed9..1efb76910 100644 --- a/slash/react/src/Form/Select/SelectInput.tsx +++ b/slash/react/src/Form/Select/SelectInput.tsx @@ -6,10 +6,15 @@ import { useId, } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { Select } from "./Select"; -type Props = ComponentProps & +type Props = ComponentProps & ComponentProps & { helpMessage?: ReactNode; }; @@ -45,7 +50,7 @@ const SelectInput = forwardRef>( required, ); return ( - >( {children} - + ); }, ); diff --git a/slash/react/src/Form/Slider/SliderInput.tsx b/slash/react/src/Form/Slider/SliderInput.tsx index 684846346..16655db78 100644 --- a/slash/react/src/Form/Slider/SliderInput.tsx +++ b/slash/react/src/Form/Slider/SliderInput.tsx @@ -1,8 +1,8 @@ import { useId, useMemo, type ComponentProps, type ReactNode } from "react"; -import { Field, HelpMessage } from "../core"; +import { HelpMessage, LegacyField } from "../core"; import { Slider } from "./Slider"; -type Props = ComponentProps & +type Props = ComponentProps & ComponentProps & { helpMessage?: ReactNode; }; @@ -26,7 +26,7 @@ const SliderInput = ({ const newId = useMemo(() => id ?? generatedId, [generatedId, id]); return ( - {children} - + ); }; diff --git a/slash/react/src/Form/Text/Text.tsx b/slash/react/src/Form/Text/Text.tsx index 39c68a18f..ca4a2e6de 100644 --- a/slash/react/src/Form/Text/Text.tsx +++ b/slash/react/src/Form/Text/Text.tsx @@ -26,6 +26,6 @@ const Text = forwardRef( }, ); -Text.displayName = "Text"; +Text.displayName = "EnhancedInput"; export { Text }; diff --git a/slash/react/src/Form/Text/TextInput.stories.tsx b/slash/react/src/Form/Text/TextInput.stories.tsx index 9ab817964..94e88cfd7 100644 --- a/slash/react/src/Form/Text/TextInput.stories.tsx +++ b/slash/react/src/Form/Text/TextInput.stories.tsx @@ -1,8 +1,8 @@ import type { Meta, StoryObj } from "@storybook/react"; import { fn } from "@storybook/test"; import { MessageTypes } from "../core"; -import { TextInput } from "./TextInput"; import { inputTypes } from "./inputTypes"; +import { TextInput } from "./TextInput"; const meta: Meta = { component: TextInput, @@ -29,6 +29,8 @@ export const TextInputStory: Story = { readOnly: false, disabled: false, autoFocus: false, + message: "message", + className: "", type: "text", label: "Your name", diff --git a/slash/react/src/Form/Text/TextInput.tsx b/slash/react/src/Form/Text/TextInput.tsx index 0a6baaf96..221cd8e82 100644 --- a/slash/react/src/Form/Text/TextInput.tsx +++ b/slash/react/src/Form/Text/TextInput.tsx @@ -1,75 +1,28 @@ -import "@axa-fr/design-system-slash-css/dist/Form/core/FormCore.scss"; -import "@axa-fr/design-system-slash-css/dist/common/grid.scss"; -import "@axa-fr/design-system-slash-css/dist/common/reboot.scss"; -import { ComponentProps, forwardRef, ReactNode, useId } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; - +import { ComponentProps, forwardRef, ReactNode } from "react"; +import { Field } from "../core"; import { Text } from "./Text"; -type Props = ComponentProps & +export type TextInputProps = ComponentProps & ComponentProps & { helpMessage?: ReactNode; }; -const TextInput = forwardRef( - ( - { - id, - message, - children, - helpMessage, - classNameContainerLabel, - classNameContainerInput, - label, - messageType, - isVisible, - className, - forceDisplayMessage, - classModifier = "", - disabled = false, - required, - ...inputTextProps - }, - inputRef, - ) => { - const inputUseId = useId(); - const inputId = id ?? inputUseId; - const { inputClassModifier, inputFieldClassModifier } = - useInputClassModifier( - classModifier, - disabled, - Boolean(children), - required, - ); - +// eslint-disable-next-line react/no-multi-comp +const TextInput = forwardRef( + ({ children, ...props }, inputRef) => { return ( - + {...props} + renderInput={({ id, classModifier }) => ( - {children} - - + )} + > + {children} ); }, diff --git a/slash/react/src/Form/Text/index.ts b/slash/react/src/Form/Text/index.ts index e13c018cf..de4b8a7a7 100644 --- a/slash/react/src/Form/Text/index.ts +++ b/slash/react/src/Form/Text/index.ts @@ -1,2 +1,2 @@ -export { TextInput } from "./TextInput"; export { Text } from "./Text"; +export { TextInput } from "./TextInput"; diff --git a/slash/react/src/Form/Textarea/TextareaInput.tsx b/slash/react/src/Form/Textarea/TextareaInput.tsx index 971bdc7cc..7d7552af1 100644 --- a/slash/react/src/Form/Textarea/TextareaInput.tsx +++ b/slash/react/src/Form/Textarea/TextareaInput.tsx @@ -2,11 +2,16 @@ import "@axa-fr/design-system-slash-css/dist/common/grid.scss"; import "@axa-fr/design-system-slash-css/dist/common/reboot.scss"; import "@axa-fr/design-system-slash-css/dist/Form/core/FormCore.scss"; import { ComponentProps, forwardRef, ReactNode, useId } from "react"; -import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core"; +import { + FieldInput, + HelpMessage, + LegacyField, + useInputClassModifier, +} from "../core"; import { Textarea } from "./Textarea"; -type Props = ComponentProps & +type Props = ComponentProps & ComponentProps & { helpMessage?: ReactNode; }; @@ -46,7 +51,7 @@ const TextareaInput = forwardRef( ); return ( - ( {children} - + ); }, ); diff --git a/slash/react/src/Form/core/Field.tsx b/slash/react/src/Form/core/Field.tsx index 5e9e7a234..83909d7d7 100644 --- a/slash/react/src/Form/core/Field.tsx +++ b/slash/react/src/Form/core/Field.tsx @@ -1,14 +1,15 @@ -import { ComponentPropsWithoutRef, ReactNode } from "react"; import classNames from "classnames"; +import { ReactNode, useId } from "react"; +import { + FieldError, + FormClassManager, + HelpMessage, + MessageTypes, + useInputClassModifier, +} from "."; import { getComponentClassName } from "../../utilities"; -import { FieldError } from "./FieldError"; -import { MessageTypes } from "./MessageTypes"; -import { FieldForm } from "./FieldForm"; -type FieldProps = Omit< - ComponentPropsWithoutRef, - "children" -> & { +type InputProps = { label: ReactNode; children?: ReactNode; id?: string; @@ -19,63 +20,87 @@ type FieldProps = Omit< roleContainer?: string; ariaLabelContainer?: string; isLabelContainerLinkedToInput?: boolean; + forceDisplayMessage?: boolean; + message?: string; + messageType?: MessageTypes; + required?: boolean; + disabled?: boolean; + helpMessage?: ReactNode; }; export const Field = ({ - id = "", - message = "", - messageType = MessageTypes.error, + classNameContainerInput = "col-md-10", + classNameContainerLabel = "col-md-2", label, - children, forceDisplayMessage, + message, + messageType, + required, classModifier = "", - className, - classNameContainerLabel = "col-md-2", - classNameContainerInput = "col-md-10", + children, + disabled = false, + helpMessage, + id, isVisible = true, roleContainer, ariaLabelContainer, isLabelContainerLinkedToInput = true, -}: FieldProps) => { + renderInput: Element, +}: InputProps & { + renderInput: (props: { id: string; classModifier: string }) => ReactNode; +}) => { + const inputUseId = useId(); + const inputId = id ?? inputUseId; + + const actualRequired = required || classModifier.includes("required"); + + const { inputClassModifier, inputFieldClassModifier } = useInputClassModifier( + classModifier, + disabled, + Boolean(children), + actualRequired, + ); + if (!isVisible) { return null; } - const componentClassName = getComponentClassName( - className, - classModifier, - "row af-form__group", + const fieldContainerClassName = getComponentClassName( + "af-form__text", + forceDisplayMessage + ? `${inputFieldClassModifier} ${FormClassManager.getModifier(messageType)}` + : inputFieldClassModifier, ); return (
- - {children} - - +
+
+ + {children} +
+ {forceDisplayMessage ? ( + + ) : ( + + )} +
); }; diff --git a/slash/react/src/Form/core/LegacyField.tsx b/slash/react/src/Form/core/LegacyField.tsx new file mode 100644 index 000000000..e2ac03405 --- /dev/null +++ b/slash/react/src/Form/core/LegacyField.tsx @@ -0,0 +1,81 @@ +import classNames from "classnames"; +import { ComponentPropsWithoutRef, ReactNode } from "react"; +import { getComponentClassName } from "../../utilities"; +import { FieldError } from "./FieldError"; +import { FieldForm } from "./FieldForm"; +import { MessageTypes } from "./MessageTypes"; + +type FieldProps = Omit< + ComponentPropsWithoutRef, + "children" +> & { + label: ReactNode; + children?: ReactNode; + id?: string; + classModifier?: string; + classNameContainerLabel?: string; + classNameContainerInput?: string; + isVisible?: boolean; + roleContainer?: string; + ariaLabelContainer?: string; + isLabelContainerLinkedToInput?: boolean; +}; + +export const LegacyField = ({ + id = "", + message = "", + messageType = MessageTypes.error, + label, + children, + forceDisplayMessage, + classModifier = "", + className, + classNameContainerLabel = "col-md-2", + classNameContainerInput = "col-md-10", + isVisible = true, + roleContainer, + ariaLabelContainer, + isLabelContainerLinkedToInput = true, +}: FieldProps) => { + if (!isVisible) { + return null; + } + + const componentClassName = getComponentClassName( + className, + classModifier, + "row af-form__group", + ); + + return ( +
+
+ +
+ + {children} + + +
+ ); +}; diff --git a/slash/react/src/Form/core/index.ts b/slash/react/src/Form/core/index.ts index 8365b9604..5a1f91354 100644 --- a/slash/react/src/Form/core/index.ts +++ b/slash/react/src/Form/core/index.ts @@ -1,18 +1,19 @@ import { ReactNode } from "react"; export { Field } from "./Field"; -export { FieldInput } from "./FieldInput"; -export { MessageTypes } from "./MessageTypes"; export { FieldError } from "./FieldError"; -export { FormClassManager } from "./FormClassManager"; export { FieldForm } from "./FieldForm"; +export { FieldInput } from "./FieldInput"; +export { FormClassManager } from "./FormClassManager"; export { HelpMessage } from "./HelpMessage"; export { InputList } from "./InputList"; +export { LegacyField } from "./LegacyField"; +export { MessageTypes } from "./MessageTypes"; -export { useInputClassModifier } from "./useInputClassModifier"; +export { getFirstId } from "./getFirstId"; export { getOptionClassName } from "./getOptionClassName"; +export { useInputClassModifier } from "./useInputClassModifier"; export { useOptionsWithId } from "./useOptionsWithId"; -export { getFirstId } from "./getFirstId"; export type Option = { id?: string;