From 6b6ae46bc69f68ff81859f65d5f8a2e11d84f8dd Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Sat, 1 Feb 2025 10:14:06 +0530 Subject: [PATCH 1/4] feat(input): adding outside-top prop --- .../components/input/label-placements.raw.jsx | 2 +- apps/docs/content/docs/components/input.mdx | 6 +++++- packages/components/input/src/input.tsx | 5 +++-- packages/components/input/src/use-input.ts | 16 +++++++++++++--- .../components/input/stories/input.stories.tsx | 13 ++++++++++--- packages/core/theme/src/components/input.ts | 6 ++++++ 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/apps/docs/content/components/input/label-placements.raw.jsx b/apps/docs/content/components/input/label-placements.raw.jsx index 428dc662bb..29be3df06c 100644 --- a/apps/docs/content/components/input/label-placements.raw.jsx +++ b/apps/docs/content/components/input/label-placements.raw.jsx @@ -1,7 +1,7 @@ import {Input} from "@heroui/react"; export default function App() { - const placements = ["inside", "outside", "outside-left"]; + const placements = ["inside", "outside", "outside-left", "outside-top"]; return (
diff --git a/apps/docs/content/docs/components/input.mdx b/apps/docs/content/docs/components/input.mdx index e5de6b73c2..44abdf666d 100644 --- a/apps/docs/content/docs/components/input.mdx +++ b/apps/docs/content/docs/components/input.mdx @@ -75,12 +75,16 @@ the end of the label and the input will be required. ### Label Placements -You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`. +You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside`, `outside-left` or `outside-top`. > **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default. +> **Note**: If the `labelPlacement` is `outside`, `label` is outside only when a placeholder is provided. + +> **Note**: If the `labelPlacement` is `outside-top` or `outside-left`, `label` is outside even if a placeholder is not provided. + ### Password Input You can use the `type` property to change the input type to `password`. diff --git a/packages/components/input/src/input.tsx b/packages/components/input/src/input.tsx index d6d646dfd5..73f9be003d 100644 --- a/packages/components/input/src/input.tsx +++ b/packages/components/input/src/input.tsx @@ -17,6 +17,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { labelPlacement, hasHelper, isOutsideLeft, + isOutsideTop, shouldLabelBeOutside, errorMessage, isInvalid, @@ -82,7 +83,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { return (
- {!isOutsideLeft ? labelContent : null} + {!isOutsideLeft && !isOutsideTop ? labelContent : null!} {innerWrapper}
{helperWrapper} @@ -115,7 +116,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { return ( - {isOutsideLeft ? labelContent : null} + {isOutsideLeft || isOutsideTop ? labelContent : null} {mainWrapper} ); diff --git a/packages/components/input/src/use-input.ts b/packages/components/input/src/use-input.ts index dd14ad7834..a45542bc5a 100644 --- a/packages/components/input/src/use-input.ts +++ b/packages/components/input/src/use-input.ts @@ -239,17 +239,26 @@ export function useInput (

Without placeholder

-
+
+

With placeholder

-
+
( labelPlacement="outside-left" placeholder="Enter your email" /> +
diff --git a/packages/core/theme/src/components/input.ts b/packages/core/theme/src/components/input.ts index 53466ea08f..9627b03306 100644 --- a/packages/core/theme/src/components/input.ts +++ b/packages/core/theme/src/components/input.ts @@ -178,6 +178,12 @@ const input = tv({ mainWrapper: "flex flex-col", label: "relative text-foreground pe-2 ps-2 pointer-events-auto", }, + "outside-top": { + base: "flex-col items-center flex-nowrap data-[has-helper=true]:items-start", + inputWrapper: "flex-1", + mainWrapper: "flex flex-col", + label: "relative text-foreground pb-2", + }, inside: { label: "cursor-text", inputWrapper: "flex-col items-start justify-center gap-0", From 190341c41ec57568cc71d0f9d7bd90f56e215a15 Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Wed, 5 Feb 2025 20:46:55 +0530 Subject: [PATCH 2/4] chore(input): add outside-top to use-label-placement hook --- packages/core/system/src/hooks/use-label-placement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/system/src/hooks/use-label-placement.ts b/packages/core/system/src/hooks/use-label-placement.ts index 33c4bfdd14..d1fec900e3 100644 --- a/packages/core/system/src/hooks/use-label-placement.ts +++ b/packages/core/system/src/hooks/use-label-placement.ts @@ -3,7 +3,7 @@ import {useMemo} from "react"; import {useProviderContext} from "../provider-context"; export function useLabelPlacement(props: { - labelPlacement?: "inside" | "outside" | "outside-left"; + labelPlacement?: "inside" | "outside" | "outside-left" | "outside-top"; label?: React.ReactNode; }) { const globalContext = useProviderContext(); From bdc94f833dd59a83710af069917cf9a47bdc9ae0 Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Sat, 8 Feb 2025 19:13:57 +0530 Subject: [PATCH 3/4] refactor(input): use old method for computing labelPlacement in 'use-input' --- packages/components/input/src/use-input.ts | 44 ++++++++++++++----- .../system/src/hooks/use-label-placement.ts | 2 +- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/packages/components/input/src/use-input.ts b/packages/components/input/src/use-input.ts index 47d0824621..0c75cb5786 100644 --- a/packages/components/input/src/use-input.ts +++ b/packages/components/input/src/use-input.ts @@ -1,13 +1,7 @@ import type {InputVariantProps, SlotsToClasses, InputSlots} from "@heroui/theme"; import type {AriaTextFieldOptions} from "@react-aria/textfield"; -import { - HTMLHeroUIProps, - mapPropsVariants, - PropGetter, - useLabelPlacement, - useProviderContext, -} from "@heroui/system"; +import {HTMLHeroUIProps, mapPropsVariants, PropGetter, useProviderContext} from "@heroui/system"; import {useSafeLayoutEffect} from "@heroui/use-safe-layout-effect"; import {AriaTextFieldProps} from "@react-types/textfield"; import {useFocusRing} from "@react-aria/focus"; @@ -20,6 +14,7 @@ import {useMemo, Ref, useCallback, useState} from "react"; import {chain, mergeProps} from "@react-aria/utils"; import {useTextField} from "@react-aria/textfield"; import {FormContext, useSlottedContext} from "@heroui/form"; +import {warn} from "@heroui/shared-utils"; export interface Props extends Omit, keyof InputVariantProps> { @@ -233,10 +228,37 @@ export function useInput(() => { + if (isFileTypeInput) { + // if `labelPlacement` is not defined, choose `outside` instead + // since the default value `inside` is not supported in file input + if (!originalProps.labelPlacement) return "outside"; + // throw a warning if `labelPlacement` is `inside` + // and change it to `outside` + if (originalProps.labelPlacement === "inside") { + warn("Input with file type doesn't support inside label. Converting to outside ..."); + + return "outside"; + } + } + if ((!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && !label) { + return "outside"; + } + + return originalProps.labelPlacement ?? "inside"; + }, [originalProps.labelPlacement, label]); const errorMessage = typeof props.errorMessage === "function" diff --git a/packages/core/system/src/hooks/use-label-placement.ts b/packages/core/system/src/hooks/use-label-placement.ts index d1fec900e3..33c4bfdd14 100644 --- a/packages/core/system/src/hooks/use-label-placement.ts +++ b/packages/core/system/src/hooks/use-label-placement.ts @@ -3,7 +3,7 @@ import {useMemo} from "react"; import {useProviderContext} from "../provider-context"; export function useLabelPlacement(props: { - labelPlacement?: "inside" | "outside" | "outside-left" | "outside-top"; + labelPlacement?: "inside" | "outside" | "outside-left"; label?: React.ReactNode; }) { const globalContext = useProviderContext(); From 146a035a8952ddfad72dcc89cce9a7eb4616d2d9 Mon Sep 17 00:00:00 2001 From: Abhinav Agarwal Date: Tue, 18 Feb 2025 22:26:51 +0530 Subject: [PATCH 4/4] fix(input): fix focus behaviouir and alignment for 'outside-top' --- .changeset/selfish-kings-clap.md | 6 +++++ packages/components/input/src/input.tsx | 2 +- packages/components/input/src/use-input.ts | 26 +-------------------- packages/core/theme/src/components/input.ts | 4 +--- 4 files changed, 9 insertions(+), 29 deletions(-) create mode 100644 .changeset/selfish-kings-clap.md diff --git a/.changeset/selfish-kings-clap.md b/.changeset/selfish-kings-clap.md new file mode 100644 index 0000000000..92e9ab27bd --- /dev/null +++ b/.changeset/selfish-kings-clap.md @@ -0,0 +1,6 @@ +--- +"@heroui/date-input": patch +"@heroui/theme": patch +--- + +add 'outside-top' prop to input diff --git a/packages/components/input/src/input.tsx b/packages/components/input/src/input.tsx index 73f9be003d..718cbad622 100644 --- a/packages/components/input/src/input.tsx +++ b/packages/components/input/src/input.tsx @@ -83,7 +83,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => { return (
- {!isOutsideLeft && !isOutsideTop ? labelContent : null!} + {!isOutsideLeft && !isOutsideTop ? labelContent : null} {innerWrapper}
{helperWrapper} diff --git a/packages/components/input/src/use-input.ts b/packages/components/input/src/use-input.ts index 0c75cb5786..33c693fe78 100644 --- a/packages/components/input/src/use-input.ts +++ b/packages/components/input/src/use-input.ts @@ -14,7 +14,6 @@ import {useMemo, Ref, useCallback, useState} from "react"; import {chain, mergeProps} from "@react-aria/utils"; import {useTextField} from "@react-aria/textfield"; import {FormContext, useSlottedContext} from "@heroui/form"; -import {warn} from "@heroui/shared-utils"; export interface Props extends Omit, keyof InputVariantProps> { @@ -228,31 +227,8 @@ export function useInput(() => { - if (isFileTypeInput) { - // if `labelPlacement` is not defined, choose `outside` instead - // since the default value `inside` is not supported in file input - if (!originalProps.labelPlacement) return "outside"; - // throw a warning if `labelPlacement` is `inside` - // and change it to `outside` - if (originalProps.labelPlacement === "inside") { - warn("Input with file type doesn't support inside label. Converting to outside ..."); - - return "outside"; - } - } if ((!originalProps.labelPlacement || originalProps.labelPlacement === "inside") && !label) { return "outside"; } diff --git a/packages/core/theme/src/components/input.ts b/packages/core/theme/src/components/input.ts index 13d0f6599c..daabfedf06 100644 --- a/packages/core/theme/src/components/input.ts +++ b/packages/core/theme/src/components/input.ts @@ -179,10 +179,8 @@ const input = tv({ label: "relative text-foreground pe-2 ps-2 pointer-events-auto", }, "outside-top": { - base: "flex-col items-center flex-nowrap data-[has-helper=true]:items-start", - inputWrapper: "flex-1", mainWrapper: "flex flex-col", - label: "relative text-foreground pb-2", + label: "relative text-foreground pb-2 pointer-events-auto", }, inside: { label: "cursor-text",