diff --git a/packages/components/src/Autocomplete/Autocomplete.rebuilt.test.tsx b/packages/components/src/Autocomplete/Autocomplete.rebuilt.test.tsx index 16cbbbe60a..381c55320c 100644 --- a/packages/components/src/Autocomplete/Autocomplete.rebuilt.test.tsx +++ b/packages/components/src/Autocomplete/Autocomplete.rebuilt.test.tsx @@ -1875,7 +1875,6 @@ describe("AutocompleteRebuilt", () => { { inputProps.onChange?.(val, evt); diff --git a/packages/components/src/Autocomplete/Autocomplete.rebuilt.tsx b/packages/components/src/Autocomplete/Autocomplete.rebuilt.tsx index 37084d845b..fcdacd66af 100644 --- a/packages/components/src/Autocomplete/Autocomplete.rebuilt.tsx +++ b/packages/components/src/Autocomplete/Autocomplete.rebuilt.tsx @@ -21,7 +21,7 @@ import { useChipNavigation } from "./hooks/useChipNavigation"; import { preventDefaultPointerDown } from "./utils/interactionUtils"; import { FloatingMenu } from "./components/FloatingMenu"; import { InputText } from "../InputText"; -import type { InputTextRebuiltProps } from "../InputText/InputText.types"; +import type { InputTextProps } from "../InputText/InputText.types"; import { FormFieldWrapper } from "../FormField"; import { mergeRefs } from "../utils/mergeRefs"; import { filterDataAttributes } from "../sharedHelpers/filterDataAttributes"; @@ -154,8 +154,7 @@ function AutocompleteRebuiltInternal< : undefined, }; - const inputProps: InputTextRebuiltProps = { - version: 2 as const, + const inputProps: InputTextProps = { value: inputValue, onChange: props.readOnly ? undefined : onInputChangeFromUser, // Ensure focus/blur callbacks still fire in readOnly mode where we don't spread getReferenceProps diff --git a/packages/components/src/Autocomplete/Autocomplete.test.tsx b/packages/components/src/Autocomplete/Autocomplete.test.tsx index 894f540bf6..72f770c621 100644 --- a/packages/components/src/Autocomplete/Autocomplete.test.tsx +++ b/packages/components/src/Autocomplete/Autocomplete.test.tsx @@ -3,7 +3,6 @@ import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import type { AnyOption, CustomOptionsMenuProp } from "."; import { Autocomplete } from "."; -import type { InputTextRef } from "../InputText"; import { Text } from "../Text"; function returnOptions(options: AnyOption[]) { @@ -245,7 +244,7 @@ describe("Autocomplete", () => { it("should focus input text", async () => { const placeholder = "Got milk?"; - const textRef = React.createRef(); + const textRef = React.createRef(); render( { const placeholder = "Got milk?"; - const textRef = React.createRef(); + const textRef = React.createRef(); render( , - ref: Ref, + ref: Ref, ) { const initialOptionsMemo = useMemo( () => mapToOptions(initialOptions), @@ -55,7 +55,7 @@ function AutocompleteInternal< null, ); const delayedSearch = useDebounce(updateSearch, debounceRate); - const inputRef = useRef(null); + const inputRef = useRef(null); useEffect(() => { delayedSearch(); @@ -69,14 +69,13 @@ function AutocompleteInternal<
& - RefAttributes, + RefAttributes, ) => ReturnType; diff --git a/packages/components/src/Autocomplete/Autocomplete.types.ts b/packages/components/src/Autocomplete/Autocomplete.types.ts index f98e703f3d..027f7d30fe 100644 --- a/packages/components/src/Autocomplete/Autocomplete.types.ts +++ b/packages/components/src/Autocomplete/Autocomplete.types.ts @@ -6,7 +6,7 @@ import type { RebuiltInputCommonProps, } from "../sharedHelpers/types"; import type { FormFieldProps } from "../FormField"; -import type { InputTextRebuiltProps, InputTextRef } from "../InputText"; +import type { InputTextProps } from "../InputText"; /** * ARIA attributes for Autocomplete with managed/orchestrated behavior. @@ -165,11 +165,6 @@ export interface AutocompleteLegacyProps< ) => | Array | Promise>; - - /** - * Validations to run on the input. - */ - readonly validations?: FormFieldProps["validations"]; } // For backward compatibility @@ -201,7 +196,7 @@ export interface MenuProps< /** * Ref to the TextInput element. */ - readonly inputRef: RefObject; + readonly inputRef: RefObject; onOptionSelect(chosenOption?: GenericOptionValue): void; readonly customRenderMenu?: ( props: CustomOptionsMenuProp, @@ -235,11 +230,8 @@ export interface CustomOptionsMenuProp< /** * Ref to the TextInput element. - * v1 provides InputTextRef; v2 provides a DOM element ref. */ - readonly inputRef: RefObject< - InputTextRef | HTMLInputElement | HTMLTextAreaElement | null - >; + readonly inputRef: RefObject; /** * Component that wraps the menu content. Used for handling keyboard scroll behavior. */ @@ -517,7 +509,7 @@ interface AutocompleteRebuiltBaseProps< */ readonly customRenderInput?: (props: { inputRef: Ref; - inputProps: InputTextRebuiltProps; + inputProps: InputTextProps; }) => React.ReactNode; /** diff --git a/packages/components/src/Autocomplete/AutocompleteV2.stories.tsx b/packages/components/src/Autocomplete/AutocompleteV2.stories.tsx index bc2426a82e..a7e66f3412 100644 --- a/packages/components/src/Autocomplete/AutocompleteV2.stories.tsx +++ b/packages/components/src/Autocomplete/AutocompleteV2.stories.tsx @@ -260,10 +260,7 @@ const TemplateEmptyStateAndActions = () => { setModalOpen(false)}> Create service - setServiceValue(val)} - /> +
@@ -76,7 +76,7 @@ exports[`Autocomplete should display headers when headers are passed in 1`] = ` autocomplete="off" class="input" id="«r5»" - type="text" + name="generatedName--«r5»" value="" /> diff --git a/packages/components/src/Autocomplete/index.tsx b/packages/components/src/Autocomplete/index.tsx index bfa62efd92..64af2003c2 100644 --- a/packages/components/src/Autocomplete/index.tsx +++ b/packages/components/src/Autocomplete/index.tsx @@ -10,7 +10,6 @@ import type { } from "./Autocomplete.types"; import { AutocompleteRebuilt } from "./Autocomplete.rebuilt"; import { Autocomplete as AutocompleteLegacy } from "./Autocomplete"; -import type { InputTextRef } from "../InputText"; export type { OptionLike } from "./Autocomplete.types"; @@ -75,7 +74,7 @@ function isNewAutocompleteProps( function AutocompleteShim( props: AutocompleteShimProps, - ref: React.Ref, + ref: React.Ref, ) { if (isNewAutocompleteProps(props)) { return ( @@ -86,7 +85,9 @@ function AutocompleteShim( ); } - return } />; + return ( + } /> + ); } const AutocompleteForwarded = forwardRef(AutocompleteShim); @@ -121,7 +122,7 @@ export const Autocomplete = AutocompleteForwarded as { GenericGetOptionsValue > & { version?: 1; - ref?: React.Ref; + ref?: React.Ref; // Disallow v2-only props for clearer DX menu?: never; }, @@ -131,7 +132,7 @@ export const Autocomplete = AutocompleteForwarded as { // eslint-disable-next-line import/no-deprecated props: AutocompleteLegacyProps & { version?: 1; - ref?: React.Ref; + ref?: React.Ref; // Disallow v2-only props for clearer DX menu?: never; }, diff --git a/packages/components/src/Card/Card.stories.tsx b/packages/components/src/Card/Card.stories.tsx index f06d9b2774..19cacdf2c3 100644 --- a/packages/components/src/Card/Card.stories.tsx +++ b/packages/components/src/Card/Card.stories.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import type { Meta, StoryObj } from "@storybook/react-vite"; import { action } from "storybook/actions"; import { Card } from "@jobber/components/Card"; @@ -47,38 +47,54 @@ type BaseStory = StoryObj; type LinkStory = StoryObj; type ClickStory = StoryObj; -const BasicTemplate = (args: BaseStory["args"]) => ( - - - Details - - - - - Contact - - - - - - - -); +const BasicTemplate = (args: BaseStory["args"]) => { + const [companyName, setCompanyName] = useState("Quest Provider"); + const [yearsInBusiness, setYearsInBusiness] = useState(""); + const [phone, setPhone] = useState(""); + const [website, setWebsite] = useState(""); + const [email, setEmail] = useState(""); + + return ( + + + Details + + + + + Contact + + + + + + + + ); +}; const LinkTemplate = (args: LinkStory["args"]) => { const linkProps = args as LinkCardArgs; @@ -144,45 +160,56 @@ export const WithElevation: BaseStory = { }, }; -const WithAccentTemplate = (args: BaseStory["args"]) => ( -
- - - Details - - - - - Contact - - - - - - - -
-); +const WithAccentTemplate = (args: BaseStory["args"]) => { + const [companyName, setCompanyName] = useState("Quest Provider"); + const [yearsInBusiness, setYearsInBusiness] = useState(""); + const [phone, setPhone] = useState(""); + const [website, setWebsite] = useState(""); + const [email, setEmail] = useState(""); + + return ( +
+ + + Details + + + + + Contact + + + + + + + +
+ ); +}; export const WithAccent: BaseStory = { render: WithAccentTemplate, @@ -255,48 +282,64 @@ export const HeaderAction: BaseStory = { render: HeaderActionTemplate, }; -const CompoundComponentTemplate = (args: BaseStory["args"]) => ( - - - - - Company settings - @@ -246,14 +262,10 @@ function MockFormWithState() { return ( - Dirty: {formState.isDirty ? "true" : "false"} Valid: {formState.isValid ? "true" : "false"} diff --git a/packages/components/src/InputDate/InputDate.rebuilt.tsx b/packages/components/src/InputDate/InputDate.rebuilt.tsx index 5713a34f37..9dc1ab83fd 100644 --- a/packages/components/src/InputDate/InputDate.rebuilt.tsx +++ b/packages/components/src/InputDate/InputDate.rebuilt.tsx @@ -111,7 +111,6 @@ export const InputDateRebuilt = forwardRef< invalid={props.invalid} required={props.required} name={props.name} - version={2} value={ showEmptyValueLabel ? props.emptyValueLabel || "" : value || "" } diff --git a/packages/components/src/InputGroup/InputGroup.stories.tsx b/packages/components/src/InputGroup/InputGroup.stories.tsx index 7b3fd174d3..1aa5b1b97e 100644 --- a/packages/components/src/InputGroup/InputGroup.stories.tsx +++ b/packages/components/src/InputGroup/InputGroup.stories.tsx @@ -31,17 +31,36 @@ const BasicTemplate = (args: Story["args"]) => { }; const NestedTemplate = (args: Story["args"]) => { + const [street1, setStreet1] = useState(""); + const [street2, setStreet2] = useState(""); + const [city, setCity] = useState(""); + const [province, setProvince] = useState(""); + const [postalCode, setPostalCode] = useState(""); + const [country, setCountry] = useState(""); + return ( - - + + - - + + - - + + ); @@ -94,19 +113,47 @@ export const DateRange: Story = { }; const VerticalWithHorizontalRowsTemplate = (args: Story["args"]) => { + const [street1, setStreet1] = useState(""); + const [street2, setStreet2] = useState(""); + const [city, setCity] = useState(""); + const [province, setProvince] = useState(""); + const [postalCode, setPostalCode] = useState(""); + const [country, setCountry] = useState(""); + const [planet, setPlanet] = useState(""); + return (
- - + + - - + + - - - + + +
diff --git a/packages/components/src/InputText/InputText.rebuilt.test.tsx b/packages/components/src/InputText/InputText.rebuilt.test.tsx deleted file mode 100644 index b21e33387d..0000000000 --- a/packages/components/src/InputText/InputText.rebuilt.test.tsx +++ /dev/null @@ -1,662 +0,0 @@ -import React from "react"; -import { fireEvent, render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { InputText } from "."; -import type { InputTextRef } from "./InputText.types"; - -// eslint-disable-next-line max-statements -describe("InputText V2 (Rebuilt)", () => { - const value = ""; - - it("renders a regular input for text and numbers", () => { - const { container } = render( - , - ); - - expect(container).toMatchSnapshot(); - }); - - it("renders a textarea with 4 rows", () => { - const { container } = render( - , - ); - expect(container).toMatchSnapshot(); - }); - - it("should call the handler with the new value", async () => { - const placeholder = "I hold places."; - const newValue = - "The snake which cannot cast its skin has to die. As well the minds which are prevented from changing their opinions; they cease to be mind."; - const newerValue = - "They always say time changes things, but you actually have to change them yourself."; - const changeHandler = jest.fn(); - - const { getByLabelText } = render( - , - ); - - fireEvent.change(getByLabelText(placeholder), { - target: { value: newValue }, - }); - expect(changeHandler).toHaveBeenCalledWith(newValue, expect.anything()); - - fireEvent.change(getByLabelText(placeholder), { - target: { value: newerValue }, - }); - expect(changeHandler).toHaveBeenCalledWith(newerValue, expect.anything()); - }); - - it("should render text description", () => { - const description = "This is a description"; - render( - , - ); - expect(screen.getByText(description)).toBeInTheDocument(); - }); - - it("should render markup description", () => { - const testId = "i-am-a-description"; - const element =
; - render( - , - ); - expect(screen.getByTestId(testId)).toBeInTheDocument(); - }); - - describe("focusing", () => { - it("should focus input text", () => { - const placeholder = "Got milk?"; - - const textRef = React.createRef(); - - const { getByLabelText } = render( - , - ); - - textRef.current?.focus(); - expect(getByLabelText(placeholder)).toHaveFocus(); - }); - - it("supports the autoFocus attribute", async () => { - const placeholder = "Got milk?"; - - const { getByLabelText } = render( - , - ); - - expect(getByLabelText(placeholder)).toHaveFocus(); - }); - }); - - it("should scroll into view input text", () => { - const scrollIntoViewMock = jest.fn(); - window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock; - - const placeholder = "Got milk?"; - - const textRef = React.createRef(); - - render( - , - ); - - textRef.current?.scrollIntoView(); - expect(scrollIntoViewMock).toHaveBeenCalled(); - }); - - describe("toolbar", () => { - describe("without toolbar", () => { - it("should not render toolbar", () => { - render( - , - ); - expect( - screen.queryByTestId("ATL-InputText-Toolbar"), - ).not.toBeInTheDocument(); - }); - }); - describe("with toolbar and toolbarVisibility always", () => { - it("should always render toolbar", () => { - render( - Bar Of Tool} - toolbarVisibility="always" - />, - ); - expect(screen.getByTestId("ATL-InputText-Toolbar")).toBeInTheDocument(); - }); - }); - - describe("with toolbar and toolbarVisibility focus-within", () => { - it("should only render toolbar when focused", () => { - render( - Bar Of Tool} - />, - ); - expect( - screen.queryByTestId("ATL-InputText-Toolbar"), - ).not.toBeInTheDocument(); - - const input = screen.getByLabelText("Favourite movie"); - fireEvent.focus(input); - - expect(screen.getByTestId("ATL-InputText-Toolbar")).toBeInTheDocument(); - }); - }); - describe("with multiline", () => { - describe("with toolbar and toolbarVisibility focus-within", () => { - it("should only render toolbar when focused", () => { - render( - Bar Of Tool} - multiline - />, - ); - expect( - screen.queryByTestId("ATL-InputText-Toolbar"), - ).not.toBeInTheDocument(); - - const input = screen.getByLabelText("Favourite movie"); - fireEvent.focus(input); - - expect( - screen.getByTestId("ATL-InputText-Toolbar"), - ).toBeInTheDocument(); - }); - }); - }); - }); - - describe("Shared HTMLInputBaseProps", () => { - it("should render with id attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute("id", "text-id"); - }); - - it("should render with name attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute("name", "text-name"); - }); - - it("should be disabled when disabled prop is true", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toBeDisabled(); - }); - - it("should not allow typing when disabled", async () => { - const changeHandler = jest.fn(); - render( - , - ); - const input = screen.getByRole("textbox"); - await userEvent.type(input, "test"); - expect(changeHandler).not.toHaveBeenCalled(); - }); - - it("should be read-only when readOnly prop is true", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute("readonly"); - }); - - it("should not allow typing when readOnly", async () => { - const changeHandler = jest.fn(); - render( - , - ); - const input = screen.getByRole("textbox"); - await userEvent.type(input, "more"); - expect(changeHandler).not.toHaveBeenCalled(); - }); - - it("should render with pattern attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute( - "pattern", - "[A-Za-z]+", - ); - }); - - it("should render with inputMode attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute( - "inputmode", - "numeric", - ); - }); - - it("should render with tabIndex attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute("tabindex", "5"); - }); - - it("should render with maxLength attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute("maxlength", "100"); - }); - - it("should render with required attribute", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toBeRequired(); - }); - }); - - describe("Shared RebuiltInputCommonProps", () => { - it("should display error message", () => { - const errorMessage = "Invalid input"; - render( - , - ); - expect(screen.getByText(errorMessage)).toBeInTheDocument(); - }); - - it("should apply invalid styling when invalid prop is true", () => { - const { container } = render( - , - ); - const wrapper = container.querySelector('[class*="wrapper"]'); - expect(wrapper).toHaveClass("invalid"); - }); - - it("should apply loading spinner class when loading prop is true", () => { - const { container } = render( - , - ); - expect(container.querySelector('[class*="spinner"]')).toBeTruthy(); - }); - - it("should render with clearable always", async () => { - const changeHandler = jest.fn(); - render( - , - ); - const clearButton = screen.getByTestId("ATL-FormField-clearButton"); - await userEvent.click(clearButton); - expect(changeHandler).toHaveBeenCalledWith(""); - }); - - it("should not render clear button when readonly with clearable always", () => { - render( - , - ); - expect( - screen.queryByTestId("ATL-FormField-clearButton"), - ).not.toBeInTheDocument(); - }); - - it("should not render clear button when disabled with clearable always", () => { - render( - , - ); - expect( - screen.queryByTestId("ATL-FormField-clearButton"), - ).not.toBeInTheDocument(); - }); - - it("should apply small size class", () => { - const { container } = render( - , - ); - const wrapper = container.querySelector('[class*="wrapper"]'); - expect(wrapper).toHaveClass("small"); - }); - - it("should apply large size class", () => { - const { container } = render( - , - ); - const wrapper = container.querySelector('[class*="wrapper"]'); - expect(wrapper).toHaveClass("large"); - }); - - it("should apply inline class", () => { - const { container } = render( - , - ); - const containerEl = container.querySelector('[class*="container"]'); - expect(containerEl).toHaveClass("inline"); - }); - - it("should render with prefix", () => { - render( - , - ); - expect(screen.getByText("$")).toBeInTheDocument(); - }); - - it("should render with suffix", () => { - render( - , - ); - expect(screen.getByText("USD")).toBeInTheDocument(); - }); - - describe("showMiniLabel", () => { - it("should hide the mini label when showMiniLabel is false and input has a value", () => { - render( - , - ); - expect(screen.queryByText("Text")).not.toBeInTheDocument(); - }); - - it("should still show the placeholder when showMiniLabel is false and input is empty", () => { - render( - , - ); - expect(screen.getByText("Text")).toBeInTheDocument(); - }); - }); - }); - - describe("Event handlers", () => { - it("should call onFocus when input is focused", async () => { - const focusHandler = jest.fn(); - render( - , - ); - await userEvent.click(screen.getByRole("textbox")); - expect(focusHandler).toHaveBeenCalledTimes(1); - }); - - it("should call onBlur when input loses focus", async () => { - const blurHandler = jest.fn(); - render( - <> - - - , - ); - const input = screen.getByRole("textbox"); - await userEvent.click(input); - await userEvent.click(screen.getByTestId("other-element")); - expect(blurHandler).toHaveBeenCalledTimes(1); - }); - - it("should call onKeyDown when key is pressed", async () => { - const keyDownHandler = jest.fn(); - render( - , - ); - const input = screen.getByRole("textbox"); - await userEvent.type(input, "a"); - expect(keyDownHandler).toHaveBeenCalled(); - }); - - it("should call onKeyUp when key is released", async () => { - const keyUpHandler = jest.fn(); - render( - , - ); - const input = screen.getByRole("textbox"); - await userEvent.type(input, "a"); - expect(keyUpHandler).toHaveBeenCalled(); - }); - - it("should call all mouse event handlers when input (textarea) is clicked", async () => { - const handlers = { - onClick: jest.fn(), - onMouseDown: jest.fn(), - onMouseUp: jest.fn(), - onPointerDown: jest.fn(), - onPointerUp: jest.fn(), - }; - render( - , - ); - const input = screen.getByRole("textbox", { name: "Text" }); - await userEvent.click(input); - - expect(handlers.onClick).toHaveBeenCalledTimes(1); - expect(handlers.onMouseDown).toHaveBeenCalledTimes(1); - expect(handlers.onMouseUp).toHaveBeenCalledTimes(1); - expect(handlers.onPointerDown).toHaveBeenCalledTimes(1); - expect(handlers.onPointerUp).toHaveBeenCalledTimes(1); - }); - - it("should call all mouse event handlers when input is clicked", async () => { - const handlers = { - onClick: jest.fn(), - onMouseDown: jest.fn(), - onMouseUp: jest.fn(), - onPointerDown: jest.fn(), - onPointerUp: jest.fn(), - }; - render( - , - ); - const input = screen.getByRole("textbox"); - await userEvent.click(input); - - expect(handlers.onClick).toHaveBeenCalledTimes(1); - expect(handlers.onMouseDown).toHaveBeenCalledTimes(1); - expect(handlers.onMouseUp).toHaveBeenCalledTimes(1); - expect(handlers.onPointerDown).toHaveBeenCalledTimes(1); - expect(handlers.onPointerUp).toHaveBeenCalledTimes(1); - }); - }); - - describe("ARIA attributes", () => { - it("should render with aria-label", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAccessibleName("Custom label"); - }); - - it("should render with aria-describedby", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute( - "aria-describedby", - "description-id", - ); - }); - - it("should render with aria-required", () => { - render( - , - ); - expect(screen.getByRole("textbox")).toHaveAttribute( - "aria-required", - "true", - ); - }); - }); -}); diff --git a/packages/components/src/InputText/InputText.rebuilt.tsx b/packages/components/src/InputText/InputText.rebuilt.tsx deleted file mode 100644 index 89ef39efbd..0000000000 --- a/packages/components/src/InputText/InputText.rebuilt.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import type { InputHTMLAttributes, TextareaHTMLAttributes } from "react"; -import React, { forwardRef, useId, useMemo } from "react"; -import type { InputTextRebuiltProps } from "./InputText.types"; -import { useTextAreaResize } from "./useTextAreaResize"; -import { useInputTextActions } from "./useInputTextActions"; -import { FormFieldWrapper, useAtlantisFormFieldName } from "../FormField"; -import { FormFieldPostFix } from "../FormField/FormFieldPostFix"; -import { mergeRefs } from "../utils/mergeRefs"; -import { filterDataAttributes } from "../sharedHelpers/filterDataAttributes"; -import formFieldStyles from "../FormField/FormField.module.css"; - -export const InputTextSPAR = forwardRef(function InputTextInternal( - props: InputTextRebuiltProps, - inputRef: React.Ref, -) { - const inputTextRef = React.useRef( - null, - ), - wrapperRef = React.useRef(null); - - const id = useInputTextId(props); - - const { rowRange } = useTextAreaResize({ - rows: props.rows, - value: props.value, - inputRef: inputTextRef, - wrapperRef: wrapperRef, - }); - - const { name } = useAtlantisFormFieldName({ - nameProp: props.name, - id: id, - }); - - const { - handleChange, - handleBlur, - handleFocus, - handleKeyDown, - handleKeyUp, - handleClear, - handleMouseDown, - handleMouseUp, - handlePointerDown, - handlePointerUp, - handleClick, - } = useInputTextActions({ - onChange: props.onChange, - onBlur: props.onBlur, - onFocus: props.onFocus, - onMouseDown: props.onMouseDown, - onMouseUp: props.onMouseUp, - onPointerDown: props.onPointerDown, - onPointerUp: props.onPointerUp, - onClick: props.onClick, - onKeyDown: props.onKeyDown, - onKeyUp: props.onKeyUp, - onEnter: props.onEnter, - inputRef: inputTextRef, - }); - - const descriptionIdentifier = `descriptionUUID--${id}`; - const descriptionVisible = props.description && !props.inline; - const isInvalid = Boolean(props.error || props.invalid); - const dataAttrs = filterDataAttributes(props); - - const mergedRef = useMemo(() => mergeRefs([inputRef, inputTextRef]), []); - - // Shared props for both TextArea and TextInput - const commonInputProps = { - id, - name, - className: formFieldStyles.input, - value: props.value, - disabled: props.disabled, - readOnly: props.readOnly, - autoFocus: props.autoFocus, - autoComplete: props.autoComplete, - inputMode: props.inputMode, - tabIndex: props.tabIndex, - maxLength: props.maxLength, - required: props.required, - role: props.role, - "aria-label": props["aria-label"], - "aria-describedby": descriptionVisible - ? descriptionIdentifier - : props["aria-describedby"], - "aria-invalid": isInvalid ? true : undefined, - "aria-controls": props["aria-controls"], - "aria-expanded": props["aria-expanded"], - "aria-activedescendant": props["aria-activedescendant"], - "aria-autocomplete": props["aria-autocomplete"], - "aria-required": props["aria-required"], - onChange: handleChange, - onBlur: handleBlur, - onFocus: handleFocus, - onKeyDown: handleKeyDown, - onKeyUp: handleKeyUp, - onMouseDown: handleMouseDown, - onMouseUp: handleMouseUp, - onPointerDown: handlePointerDown, - onPointerUp: handlePointerUp, - onClick: handleClick, - ref: mergedRef, - ...dataAttrs, - }; - - return ( - - <> - {props.multiline ? ( -