mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 11:27:32 +00:00
feat(ui): implemented new input component
This commit is contained in:
@@ -0,0 +1,66 @@
|
|||||||
|
import { faEye, faMailBulk } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Input } from './Input';
|
||||||
|
|
||||||
|
const meta: Meta<typeof Input> = {
|
||||||
|
title: 'Components/Input',
|
||||||
|
component: Input,
|
||||||
|
tags: ['v2'],
|
||||||
|
argTypes: {
|
||||||
|
isRounded: {
|
||||||
|
defaultValue: true,
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
defaultValue: 'Type anything',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Input>;
|
||||||
|
|
||||||
|
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||||
|
export const Filled: Story = {
|
||||||
|
args: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Outline: Story = {
|
||||||
|
args: {
|
||||||
|
variant: 'outline'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Plain: Story = {
|
||||||
|
args: {
|
||||||
|
variant: 'plain'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Error: Story = {
|
||||||
|
args: {
|
||||||
|
isError: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AutoWidth: Story = {
|
||||||
|
args: {
|
||||||
|
isFullWidth: false,
|
||||||
|
className: 'w-auto'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RightIcon: Story = {
|
||||||
|
args: {
|
||||||
|
rightIcon: <FontAwesomeIcon icon={faEye} />
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LeftIcon: Story = {
|
||||||
|
args: {
|
||||||
|
leftIcon: <FontAwesomeIcon icon={faMailBulk} />
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import { forwardRef, InputHTMLAttributes, ReactNode } from 'react';
|
||||||
|
import { cva, VariantProps } from 'cva';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
placeholder?: string;
|
||||||
|
isFullWidth?: boolean;
|
||||||
|
isRequired?: boolean;
|
||||||
|
leftIcon?: ReactNode;
|
||||||
|
rightIcon?: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputVariants = cva(
|
||||||
|
'input w-full py-2 text-gray-400 placeholder-gray-500 placeholder-opacity-50',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
size: {
|
||||||
|
xs: ['text-xs'],
|
||||||
|
sm: ['text-sm'],
|
||||||
|
md: ['text-md'],
|
||||||
|
lg: ['text-lg']
|
||||||
|
},
|
||||||
|
isRounded: {
|
||||||
|
true: ['rounded-md'],
|
||||||
|
false: ''
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
filled: ['bg-bunker-800', 'text-gray-400'],
|
||||||
|
outline: ['bg-transparent'],
|
||||||
|
plain: 'bg-transparent outline-none'
|
||||||
|
},
|
||||||
|
isError: {
|
||||||
|
true: 'focus:ring-red/50 placeholder-red-300',
|
||||||
|
false: 'focus:ring-primary/50'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
compoundVariants: []
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const inputParentContainerVariants = cva('inline-flex items-center border relative', {
|
||||||
|
variants: {
|
||||||
|
isRounded: {
|
||||||
|
true: ['rounded-md'],
|
||||||
|
false: ''
|
||||||
|
},
|
||||||
|
isError: {
|
||||||
|
true: 'border-red',
|
||||||
|
false: 'border-mineshaft-400'
|
||||||
|
},
|
||||||
|
isFullWidth: {
|
||||||
|
true: 'w-full',
|
||||||
|
false: ''
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
filled: ['bg-bunker-800', 'text-gray-400'],
|
||||||
|
outline: ['bg-transparent'],
|
||||||
|
plain: 'border-none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> &
|
||||||
|
VariantProps<typeof inputVariants> &
|
||||||
|
Props;
|
||||||
|
|
||||||
|
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
className,
|
||||||
|
isRounded = true,
|
||||||
|
isFullWidth = true,
|
||||||
|
isError = false,
|
||||||
|
isRequired,
|
||||||
|
leftIcon,
|
||||||
|
rightIcon,
|
||||||
|
variant = 'filled',
|
||||||
|
size = 'md',
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div className={inputParentContainerVariants({ isRounded, isError, isFullWidth, variant })}>
|
||||||
|
{leftIcon && <span className="absolute left-0 ml-2">{leftIcon}</span>}
|
||||||
|
<input
|
||||||
|
{...props}
|
||||||
|
required={isRequired}
|
||||||
|
ref={ref}
|
||||||
|
className={twMerge(
|
||||||
|
leftIcon ? 'pl-9' : 'pl-4',
|
||||||
|
rightIcon ? 'pr-9' : 'pr-4',
|
||||||
|
inputVariants({ className, isError, size, isRounded, variant })
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{rightIcon && <span className="absolute right-0 mr-2">{rightIcon}</span>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Input.displayName = 'Input';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export type { InputProps } from './Input';
|
||||||
|
export { Input } from './Input';
|
||||||
Reference in New Issue
Block a user