diff --git a/packages/documentation/src/stories/TextInput.stories.tsx b/packages/documentation/src/stories/TextInput.stories.tsx index 0d05f84c..b860c729 100644 --- a/packages/documentation/src/stories/TextInput.stories.tsx +++ b/packages/documentation/src/stories/TextInput.stories.tsx @@ -1,10 +1,10 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { TextInput } from "@versini/ui-components"; +import { Button, TextInput } from "@versini/ui-components"; const meta: Meta = { component: TextInput, parameters: { - controls: { exclude: ["spacing"], sort: "requiredFirst" }, + controls: { exclude: ["spacing", "rightElement"], sort: "requiredFirst" }, }, args: { type: "text", @@ -72,3 +72,23 @@ export const Basic: Story = { ), }; + +export const RightElement: Story = { + args: { + rightElement: ( + + ), + helperText: "Powered by the sun", + }, + render: (args) => ( +
+
+
+ +
+
+
+ ), +}; diff --git a/packages/ui-components/src/components/TextInput/TextInput.tsx b/packages/ui-components/src/components/TextInput/TextInput.tsx index 6c5f939a..792d4e13 100644 --- a/packages/ui-components/src/components/TextInput/TextInput.tsx +++ b/packages/ui-components/src/components/TextInput/TextInput.tsx @@ -23,6 +23,8 @@ export const TextInput = ({ helperText = "", + rightElement, + ...extraProps }: TextInputProps) => { const inputId = useUniqueId({ id, prefix: "av-text-input-" }); @@ -74,6 +76,11 @@ export const TextInput = ({ {helperText} )} + + {rightElement && ( + {rightElement} + )} + {error && helperText && ( {liveErrorMessage} diff --git a/packages/ui-components/src/components/TextInput/TextInputTypes.d.ts b/packages/ui-components/src/components/TextInput/TextInputTypes.d.ts index 4ca439d8..6bc02bca 100644 --- a/packages/ui-components/src/components/TextInput/TextInputTypes.d.ts +++ b/packages/ui-components/src/components/TextInput/TextInputTypes.d.ts @@ -10,4 +10,5 @@ export type TextInputProps = { raw?: boolean; noBorder?: boolean; inputClassName?: string; + rightElement?: React.ReactElement; } & React.InputHTMLAttributes; diff --git a/packages/ui-components/src/components/TextInput/__tests__/TextInput.test.tsx b/packages/ui-components/src/components/TextInput/__tests__/TextInput.test.tsx index 82ab980d..e989d4de 100644 --- a/packages/ui-components/src/components/TextInput/__tests__/TextInput.test.tsx +++ b/packages/ui-components/src/components/TextInput/__tests__/TextInput.test.tsx @@ -58,7 +58,13 @@ describe("TextInput modifiers", () => { ); const input = await screen.findByTestId("txtnpt-1"); expect(input.className).not.toContain("toto"); - expect(input.parentElement?.className).toContain("toto"); + if (input.parentElement) { + expectToHaveClasses(input.parentElement, [ + "toto", + "w-full", + "justify-center", + ]); + } }); it("should render a text input with an input class", async () => { @@ -74,6 +80,21 @@ describe("TextInput modifiers", () => { expect(input.className).toContain("toto"); expect(input.parentElement?.className).not.toContain("toto"); }); + + it("should render a text input with a right element", async () => { + render( + right element} + data-testid="txtnpt-1" + />, + ); + const rightElement = await screen.findByText("right element"); + expect(rightElement?.parentElement?.className).toContain( + "av-text-input__control--right", + ); + }); }); describe("TextInput methods", () => { diff --git a/packages/ui-components/src/components/TextInput/utilities.ts b/packages/ui-components/src/components/TextInput/utilities.ts index 84c7e063..f5905dfc 100644 --- a/packages/ui-components/src/components/TextInput/utilities.ts +++ b/packages/ui-components/src/components/TextInput/utilities.ts @@ -117,7 +117,7 @@ export const getTextInputClasses = ({ }: getTextInputClassesProps) => { const wrapper = raw ? className - : clsx(`${TEXT_INPUT_WRAPPER_CLASSNAME} w-full`, className); + : clsx(`${TEXT_INPUT_WRAPPER_CLASSNAME} w-full justify-center`, className); const input = raw ? inputClassName diff --git a/packages/ui-components/src/components/index.css b/packages/ui-components/src/components/index.css index 7d2eae7b..b5f48cdb 100644 --- a/packages/ui-components/src/components/index.css +++ b/packages/ui-components/src/components/index.css @@ -28,7 +28,7 @@ .av-text-input-wrapper label { position: absolute; /* move the label inline */ - transform: translate(18px, 28px) scale(1); + transform: translate(18px, 0) scale(1); transform-origin: top left; transition: all 0.2s ease-out; } @@ -53,13 +53,18 @@ .av-text-input:focus + label, .av-text-input:not(:placeholder-shown) + label { /* move the label up */ - transform: translate(18px, 2px) scale(0.75); + transform: translate(18px, -25px) scale(0.75); } .av-text-input-helper-text { position: absolute; - transform: translate(18px, 59px) scale(0.75); + transform: translate(18px, 30px) scale(0.75); transform-origin: top left; transition: all 0.2s ease-out; } + + .av-text-input__control--right { + position: absolute; + right: 18px; + } }