Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(input): adding outside-top prop #4775

Open
wants to merge 6 commits into
base: canary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex flex-col gap-4">
Expand Down
6 changes: 5 additions & 1 deletion apps/docs/content/docs/components/input.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

<CodeDemo title="Label Placements" files={inputContent.labelPlacements} />

> **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`.
Expand Down
5 changes: 3 additions & 2 deletions packages/components/input/src/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {
labelPlacement,
hasHelper,
isOutsideLeft,
isOutsideTop,
shouldLabelBeOutside,
errorMessage,
isInvalid,
Expand Down Expand Up @@ -82,7 +83,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {
return (
<div {...getMainWrapperProps()}>
<div {...getInputWrapperProps()}>
{!isOutsideLeft ? labelContent : null}
{!isOutsideLeft && !isOutsideTop ? labelContent : null!}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why null!?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe added by mistake. I don't remember adding it

{innerWrapper}
</div>
{helperWrapper}
Expand Down Expand Up @@ -115,7 +116,7 @@ const Input = forwardRef<"input", InputProps>((props, ref) => {

return (
<Component {...getBaseProps()}>
{isOutsideLeft ? labelContent : null}
{isOutsideLeft || isOutsideTop ? labelContent : null}
{mainWrapper}
</Component>
);
Expand Down
16 changes: 13 additions & 3 deletions packages/components/input/src/use-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,26 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
const hasPlaceholder = !!props.placeholder;
const hasLabel = !!label;
const hasHelper = !!description || !!errorMessage;
const shouldLabelBeOutside = labelPlacement === "outside" || labelPlacement === "outside-left";
const isOutsideLeft = labelPlacement === "outside-left";
const isOutsideTop = labelPlacement === "outside-top";

const shouldLabelBeOutside =
// label is outside only when some placeholder is there
labelPlacement === "outside" ||
// label is outside regardless of placeholder
isOutsideLeft ||
isOutsideTop;

const shouldLabelBeInside = labelPlacement === "inside";
const isPlaceholderShown = domRef.current
? (!domRef.current.value || domRef.current.value === "" || !inputValue || inputValue === "") &&
hasPlaceholder
: false;
const isOutsideLeft = labelPlacement === "outside-left";

const hasStartContent = !!startContent;
const isLabelOutside = shouldLabelBeOutside
? labelPlacement === "outside-left" ||
? isOutsideLeft ||
isOutsideTop ||
hasPlaceholder ||
(labelPlacement === "outside" && hasStartContent)
: false;
Expand Down Expand Up @@ -526,6 +535,7 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
hasStartContent,
isLabelOutside,
isOutsideLeft,
isOutsideTop,
isLabelOutsideAsPlaceholder,
shouldLabelBeOutside,
shouldLabelBeInside,
Expand Down
13 changes: 10 additions & 3 deletions packages/components/input/stories/input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default {
control: {
type: "select",
},
options: ["inside", "outside", "outside-left"],
options: ["inside", "outside", "outside-left", "outside-top"],
},
isDisabled: {
control: {
Expand Down Expand Up @@ -175,15 +175,16 @@ const LabelPlacementTemplate = (args) => (
<div className="w-full flex flex-col items-center gap-12">
<div className="flex flex-col gap-3">
<h3>Without placeholder</h3>
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<div className="w-full flex flex-row items-end gap-4">
<Input {...args} description="inside" />
<Input {...args} description="outside" labelPlacement="outside" />
<Input {...args} description="outside-left" labelPlacement="outside-left" />
<Input {...args} description="outside-top" labelPlacement="outside-top" />
</div>
</div>
<div className="flex flex-col gap-3">
<h3>With placeholder</h3>
<div className="w-full max-w-xl flex flex-row items-end gap-4">
<div className="w-full flex flex-row items-end gap-4">
<Input {...args} description="inside" placeholder="Enter your email" />
<Input
{...args}
Expand All @@ -197,6 +198,12 @@ const LabelPlacementTemplate = (args) => (
labelPlacement="outside-left"
placeholder="Enter your email"
/>
<Input
{...args}
description="outside-top"
labelPlacement="outside-top"
placeholder="Enter your email"
/>
</div>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions packages/core/theme/src/components/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading