feat(input): styles fixed, input focus when wrapper is clicked applied

This commit is contained in:
Junior Garcia 2023-04-03 12:36:42 -03:00
parent b6c3c68f7a
commit 325a139f10
4 changed files with 150 additions and 39 deletions

View File

@ -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 {

View File

@ -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,
},
};
};

View File

@ -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,

View File

@ -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