mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(input): styles fixed, input focus when wrapper is clicked applied
This commit is contained in:
parent
b6c3c68f7a
commit
325a139f10
@ -4,7 +4,8 @@ import {useMemo} from "react";
|
||||
|
||||
import {UseInputProps, useInput} from "./use-input";
|
||||
|
||||
export interface InputProps extends Omit<UseInputProps, "ref" | "isClearButtonFocusVisible"> {}
|
||||
export interface InputProps
|
||||
extends Omit<UseInputProps, "ref" | "isClearButtonFocusVisible" | "isLabelPlaceholder"> {}
|
||||
|
||||
const Input = forwardRef<InputProps, "input">((props, ref) => {
|
||||
const {
|
||||
|
||||
@ -174,11 +174,22 @@ export function useInput(originalProps: UseInputProps) {
|
||||
};
|
||||
|
||||
const getInputWrapperProps: PropGetter = (props = {}) => {
|
||||
const canFocusInput = domRef.current && !startContent && !endContent;
|
||||
|
||||
return {
|
||||
className: slots.inputWrapper({
|
||||
class: clsx(styles?.inputWrapper, !!inputValue ? "is-filled" : ""),
|
||||
}),
|
||||
onClick: () => {
|
||||
if (canFocusInput) {
|
||||
domRef.current.focus();
|
||||
}
|
||||
},
|
||||
...props,
|
||||
style: {
|
||||
cursor: canFocusInput ? "text" : "default",
|
||||
...props.style,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ export default {
|
||||
labelPosition: {
|
||||
control: {
|
||||
type: "select",
|
||||
options: ["outside", "outside-left", "inside"],
|
||||
options: ["inside", "outside", "outside-left"],
|
||||
},
|
||||
},
|
||||
isDisabled: {
|
||||
@ -70,6 +70,13 @@ const Template: ComponentStory<typeof Input> = (args: InputProps) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
const MirrorTemplate: ComponentStory<typeof Input> = (args: InputProps) => (
|
||||
<div className="w-full max-w-xl flex flex-row gap-4">
|
||||
<Input {...args} />
|
||||
<Input {...args} placeholder="Enter your email" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const PasswordTemplate: ComponentStory<typeof Input> = (args: InputProps) => {
|
||||
const [isPasswordVisible, setIsPasswordVisible] = React.useState(false);
|
||||
|
||||
@ -131,10 +138,17 @@ const ControlledTemplate: ComponentStory<typeof Input> = (args: InputProps) => {
|
||||
};
|
||||
|
||||
const LabelPositionTemplate: ComponentStory<typeof Input> = (args: InputProps) => (
|
||||
<div className="w-full max-w-xl flex flex-row items-end gap-4">
|
||||
<Input {...args} />
|
||||
<Input {...args} labelPosition="outside" />
|
||||
<Input {...args} labelPosition="outside-left" />
|
||||
<div className="w-full flex flex-col items-center gap-12">
|
||||
<div className="w-full max-w-xl flex flex-row items-end gap-4">
|
||||
<Input {...args} />
|
||||
<Input {...args} labelPosition="outside" />
|
||||
<Input {...args} labelPosition="outside-left" />
|
||||
</div>
|
||||
<div className="w-full max-w-xl flex flex-row items-end gap-4">
|
||||
<Input {...args} placeholder="Enter your email" />
|
||||
<Input {...args} labelPosition="outside" placeholder="Enter your email" />
|
||||
<Input {...args} labelPosition="outside-left" placeholder="Enter your email" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -251,7 +265,7 @@ const StartAndEndContentTemplate: ComponentStory<typeof Input> = (args: InputPro
|
||||
{...args}
|
||||
endContent={
|
||||
<div className="pointer-events-none flex items-center">
|
||||
<span className="text-neutral-400 text-sm">.org/</span>
|
||||
<span className="text-neutral-400 text-sm">.org</span>
|
||||
</div>
|
||||
}
|
||||
label="Website"
|
||||
@ -327,18 +341,12 @@ const CustomWithStylesTemplate: ComponentStory<typeof Input> = (args: InputProps
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
export const Default = MirrorTemplate.bind({});
|
||||
Default.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
export const WithPlaceholder = Template.bind({});
|
||||
WithPlaceholder.args = {
|
||||
...defaultProps,
|
||||
placeholder: "Enter your email",
|
||||
};
|
||||
|
||||
export const Required = Template.bind({});
|
||||
export const Required = MirrorTemplate.bind({});
|
||||
Required.args = {
|
||||
...defaultProps,
|
||||
isRequired: true,
|
||||
@ -360,7 +368,7 @@ ReadOnly.args = {
|
||||
isReadOnly: true,
|
||||
};
|
||||
|
||||
export const WithDescription = Template.bind({});
|
||||
export const WithDescription = MirrorTemplate.bind({});
|
||||
WithDescription.args = {
|
||||
...defaultProps,
|
||||
description: "We'll never share your email with anyone else.",
|
||||
@ -409,12 +417,6 @@ StartAndEndContent.args = {
|
||||
labelPosition: "outside",
|
||||
};
|
||||
|
||||
export const LabelPositionWithPlaceholder = LabelPositionTemplate.bind({});
|
||||
LabelPositionWithPlaceholder.args = {
|
||||
...defaultProps,
|
||||
placeholder: "Enter your email",
|
||||
};
|
||||
|
||||
export const WithErrorMessage = Template.bind({});
|
||||
WithErrorMessage.args = {
|
||||
...defaultProps,
|
||||
|
||||
@ -27,7 +27,7 @@ const input = tv({
|
||||
base: "flex flex-col gap-2",
|
||||
label: "block text-sm font-medium text-neutral-600",
|
||||
inputWrapper: "relative w-full inline-flex flex-row items-center shadow-sm px-3 gap-3",
|
||||
innerWrapper: "inline-flex items-center w-full gap-1.5 box-border",
|
||||
innerWrapper: "inline-flex h-full items-center w-full gap-1.5 box-border",
|
||||
input: "w-full h-full bg-transparent outline-none placeholder:text-neutral-500",
|
||||
clearButton: [
|
||||
"z-10",
|
||||
@ -70,6 +70,8 @@ const input = tv({
|
||||
underlined: {
|
||||
inputWrapper: [
|
||||
"!px-1",
|
||||
"!pb-0",
|
||||
"!gap-0",
|
||||
"relative",
|
||||
"box-border",
|
||||
"border-b-2",
|
||||
@ -161,10 +163,13 @@ const input = tv({
|
||||
},
|
||||
},
|
||||
labelPosition: {
|
||||
outside: {},
|
||||
outside: {
|
||||
label: "text-foreground",
|
||||
},
|
||||
"outside-left": {
|
||||
base: "flex-row items-center flex-wrap",
|
||||
inputWrapper: "flex-1",
|
||||
label: "text-foreground",
|
||||
},
|
||||
inside: {
|
||||
label: "text-xs",
|
||||
@ -220,6 +225,7 @@ const input = tv({
|
||||
inputWrapper: "transition-background motion-reduce:transition-none !duration-150",
|
||||
label: [
|
||||
"will-change-auto",
|
||||
"origin-top-left",
|
||||
"transition-all",
|
||||
"!duration-200",
|
||||
"!ease-[cubic-bezier(0,0,0.2,1)]",
|
||||
@ -240,7 +246,7 @@ const input = tv({
|
||||
disableAnimation: false,
|
||||
},
|
||||
compoundVariants: [
|
||||
// flat & faded & color
|
||||
// flat & color
|
||||
{
|
||||
variant: "flat",
|
||||
color: "primary",
|
||||
@ -316,40 +322,40 @@ const input = tv({
|
||||
variant: "faded",
|
||||
color: "primary",
|
||||
class: {
|
||||
inputWrapper: "text-primary",
|
||||
input: "placeholder:text-primary",
|
||||
label: "text-primary",
|
||||
inputWrapper: "hover:border-primary focus-within:border-primary",
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: "faded",
|
||||
color: "secondary",
|
||||
class: {
|
||||
inputWrapper: "text-secondary",
|
||||
input: "placeholder:text-secondary",
|
||||
label: "text-secondary",
|
||||
inputWrapper: "hover:border-secondary focus-within:border-secondary",
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: "faded",
|
||||
color: "success",
|
||||
class: {
|
||||
inputWrapper: "text-success",
|
||||
input: "placeholder:text-success",
|
||||
label: "text-success",
|
||||
inputWrapper: "hover:border-success focus-within:border-success",
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: "faded",
|
||||
color: "warning",
|
||||
class: {
|
||||
inputWrapper: "text-warning",
|
||||
input: "placeholder:text-warning",
|
||||
label: "text-warning",
|
||||
inputWrapper: "hover:border-warning focus-within:border-warning",
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: "faded",
|
||||
color: "danger",
|
||||
class: {
|
||||
inputWrapper: "text-danger",
|
||||
input: "placeholder:text-danger",
|
||||
label: "text-danger",
|
||||
inputWrapper: "hover:border-danger focus-within:border-danger",
|
||||
},
|
||||
},
|
||||
// underlined & color
|
||||
@ -537,7 +543,7 @@ const input = tv({
|
||||
inputWrapper: "h-20 p-4 gap-2",
|
||||
},
|
||||
},
|
||||
// !isLabelPlaceholder & labelPosition
|
||||
// isLabelPlaceholder & labelPosition
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
labelPosition: ["inside", "outside"],
|
||||
@ -546,9 +552,9 @@ const input = tv({
|
||||
"font-normal",
|
||||
"text-neutral-500",
|
||||
"group-focus-within:font-medium",
|
||||
"group-focus-within:text-neutral-600",
|
||||
"group-[.is-filled]:font-medium",
|
||||
"group-[.is-filled]:text-neutral-600",
|
||||
"group-focus-within:pointer-events-auto",
|
||||
"group-[.is-filled]:pointer-events-auto",
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -557,6 +563,7 @@ const input = tv({
|
||||
labelPosition: "inside",
|
||||
class: {
|
||||
inputWrapper: "group",
|
||||
label: ["group-focus-within:text-neutral-600", "group-[.is-filled]:text-neutral-600"],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -564,7 +571,97 @@ const input = tv({
|
||||
labelPosition: "outside",
|
||||
class: {
|
||||
base: "group relative justify-end",
|
||||
label: ["group-focus-within:left-0", "group-[.is-filled]:left-0"],
|
||||
label: [
|
||||
"group-focus-within:left-0",
|
||||
"group-[.is-filled]:left-0",
|
||||
"group-focus-within:text-foreground",
|
||||
"group-[.is-filled]:text-foreground",
|
||||
],
|
||||
},
|
||||
},
|
||||
// isLabelPlaceholder & color
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
color: "primary",
|
||||
class: {
|
||||
label: ["group-focus-within:text-primary", "group-[.is-filled]:text-primary"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
color: "secondary",
|
||||
class: {
|
||||
label: ["group-focus-within:text-secondary", "group-[.is-filled]:text-secondary"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
color: "success",
|
||||
class: {
|
||||
label: ["group-focus-within:text-success", "group-[.is-filled]:text-success"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
color: "warning",
|
||||
class: {
|
||||
label: ["group-focus-within:text-warning", "group-[.is-filled]:text-warning"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
color: "danger",
|
||||
class: {
|
||||
label: ["group-focus-within:text-danger", "group-[.is-filled]:text-danger"],
|
||||
},
|
||||
},
|
||||
// isLabelPlaceholder & underlined
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
variant: "underlined",
|
||||
class: {
|
||||
label: ["group-focus-within:pt-0", "group-[.is-filled]:pt-0"],
|
||||
},
|
||||
},
|
||||
// isLabelPlaceholder & underlined & size
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
variant: "underlined",
|
||||
size: "xs",
|
||||
class: {
|
||||
label: ["pt-2"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
variant: "underlined",
|
||||
size: "sm",
|
||||
class: {
|
||||
label: ["pt-3"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
variant: "underlined",
|
||||
size: "md",
|
||||
class: {
|
||||
label: ["pt-4"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
variant: "underlined",
|
||||
size: "lg",
|
||||
class: {
|
||||
label: ["pt-5"],
|
||||
},
|
||||
},
|
||||
{
|
||||
isLabelPlaceholder: true,
|
||||
variant: "underlined",
|
||||
size: "xl",
|
||||
class: {
|
||||
label: ["pt-6"],
|
||||
},
|
||||
},
|
||||
// isLabelPlaceholder & inside & size
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user