mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(ui): added icon button component, updated secondary button style and added select to barrel export
This commit is contained in:
@@ -24,16 +24,16 @@ const buttonVariants = cva(
|
|||||||
variants: {
|
variants: {
|
||||||
colorSchema: {
|
colorSchema: {
|
||||||
primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'],
|
primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'],
|
||||||
secondary: ['bg-mineshaft-200', 'text-white', 'border-mineshaft-200'],
|
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'],
|
||||||
danger: ['bg-red', 'text-white', 'border-red']
|
danger: ['bg-red', 'text-white', 'border-red']
|
||||||
},
|
},
|
||||||
variant: {
|
variant: {
|
||||||
solid: '',
|
solid: '',
|
||||||
outline: ['bg-transparent', 'border', 'border-solid'],
|
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
||||||
plain: ''
|
plain: ''
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'bg-opacity-70',
|
true: 'bg-opacity-70 cursor-not-allowed',
|
||||||
false: ''
|
false: ''
|
||||||
},
|
},
|
||||||
isFullWidth: {
|
isFullWidth: {
|
||||||
@@ -60,7 +60,7 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
colorSchema: 'secondary',
|
colorSchema: 'secondary',
|
||||||
variant: 'outline',
|
variant: 'outline',
|
||||||
className: 'text-mineshaft-200 hover:bg-mineshaft-400 hover:text-white'
|
className: 'hover:bg-mineshaft'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'danger',
|
colorSchema: 'danger',
|
||||||
@@ -75,7 +75,7 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
colorSchema: 'secondary',
|
colorSchema: 'secondary',
|
||||||
variant: 'plain',
|
variant: 'plain',
|
||||||
className: 'text-mineshaft-400'
|
className: 'text-mineshaft'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'danger',
|
colorSchema: 'danger',
|
||||||
@@ -139,7 +139,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|||||||
src="/images/loading/loadingblack.gif"
|
src="/images/loading/loadingblack.gif"
|
||||||
width={36}
|
width={36}
|
||||||
alt="loading animation"
|
alt="loading animation"
|
||||||
className="rounded-xl absolute"
|
className="absolute rounded-xl"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
|
|||||||
60
frontend/src/components/v2/IconButton/IconButton.stories.tsx
Normal file
60
frontend/src/components/v2/IconButton/IconButton.stories.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { IconButton } from './IconButton';
|
||||||
|
|
||||||
|
const meta: Meta<typeof IconButton> = {
|
||||||
|
title: 'Components/IconButton',
|
||||||
|
component: IconButton,
|
||||||
|
tags: ['v2'],
|
||||||
|
argTypes: {
|
||||||
|
isRounded: {
|
||||||
|
defaultValue: true,
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
ariaLabel: {
|
||||||
|
defaultValue: 'Some buttons...'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof IconButton>;
|
||||||
|
|
||||||
|
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||||
|
export const Primary: Story = {
|
||||||
|
args: {
|
||||||
|
children: <FontAwesomeIcon icon={faPlus} />
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Secondary: Story = {
|
||||||
|
args: {
|
||||||
|
children: <FontAwesomeIcon icon={faPlus} />,
|
||||||
|
colorSchema: 'secondary',
|
||||||
|
variant: 'outline'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Danger: Story = {
|
||||||
|
args: {
|
||||||
|
children: <FontAwesomeIcon icon={faPlus} />,
|
||||||
|
colorSchema: 'danger',
|
||||||
|
variant: 'solid'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Plain: Story = {
|
||||||
|
args: {
|
||||||
|
children: <FontAwesomeIcon icon={faPlus} />,
|
||||||
|
variant: 'plain'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Disabled: Story = {
|
||||||
|
args: {
|
||||||
|
children: <FontAwesomeIcon icon={faPlus} />,
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
};
|
||||||
131
frontend/src/components/v2/IconButton/IconButton.tsx
Normal file
131
frontend/src/components/v2/IconButton/IconButton.tsx
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import { ButtonHTMLAttributes, forwardRef, ReactNode } from 'react';
|
||||||
|
import { cva, VariantProps } from 'cva';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: ReactNode;
|
||||||
|
// This is kept as required because by accessibility convention and eslint
|
||||||
|
// when button doesn't have text an aria-label needs to be passed
|
||||||
|
ariaLabel: string;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const iconButtonVariants = cva(
|
||||||
|
[
|
||||||
|
'button',
|
||||||
|
'transition-all',
|
||||||
|
'font-medium',
|
||||||
|
'cursor-pointer',
|
||||||
|
'inline-flex items-center justify-center',
|
||||||
|
'relative'
|
||||||
|
],
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
colorSchema: {
|
||||||
|
primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'],
|
||||||
|
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'],
|
||||||
|
danger: ['bg-red', 'text-white', 'border-red']
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
solid: '',
|
||||||
|
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
||||||
|
plain: ''
|
||||||
|
},
|
||||||
|
isDisabled: {
|
||||||
|
true: 'bg-opacity-70 cursor-not-allowed',
|
||||||
|
false: ''
|
||||||
|
},
|
||||||
|
isRounded: {
|
||||||
|
true: 'rounded-md',
|
||||||
|
false: ''
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
xs: ['text-xs', 'py-1', 'px-2'],
|
||||||
|
sm: ['text-sm', 'py-2', 'px-3'],
|
||||||
|
md: ['text-md', 'py-3', 'px-4'],
|
||||||
|
lg: ['text-lg', 'py-3', 'px-6']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
compoundVariants: [
|
||||||
|
{
|
||||||
|
colorSchema: 'primary',
|
||||||
|
variant: 'outline',
|
||||||
|
className: 'text-primary hover:bg-primary hover:text-black'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'secondary',
|
||||||
|
variant: 'outline',
|
||||||
|
className: 'hover:bg-mineshaft'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'danger',
|
||||||
|
variant: 'outline',
|
||||||
|
className: 'text-red hover:bg-red hover:text-black'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'primary',
|
||||||
|
variant: 'plain',
|
||||||
|
className: 'text-primary'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'secondary',
|
||||||
|
variant: 'plain',
|
||||||
|
className: 'text-mineshaft'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'danger',
|
||||||
|
variant: 'plain',
|
||||||
|
className: 'text-red'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: ['danger', 'primary', 'secondary'],
|
||||||
|
variant: ['plain'],
|
||||||
|
className: 'bg-transparent py-1 px-1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export type IconButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'aria-label'> &
|
||||||
|
VariantProps<typeof iconButtonVariants> &
|
||||||
|
Props;
|
||||||
|
|
||||||
|
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
children,
|
||||||
|
ariaLabel,
|
||||||
|
isDisabled = false,
|
||||||
|
className,
|
||||||
|
size = 'md',
|
||||||
|
variant = 'solid',
|
||||||
|
isRounded = true,
|
||||||
|
colorSchema = 'primary',
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
): JSX.Element => (
|
||||||
|
<button
|
||||||
|
ref={ref}
|
||||||
|
aria-disabled={isDisabled}
|
||||||
|
type="button"
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
className={twMerge(
|
||||||
|
iconButtonVariants({
|
||||||
|
className,
|
||||||
|
colorSchema,
|
||||||
|
size,
|
||||||
|
variant,
|
||||||
|
isRounded,
|
||||||
|
isDisabled
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
disabled={isDisabled}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
IconButton.displayName = 'IconButton';
|
||||||
2
frontend/src/components/v2/IconButton/index.tsx
Normal file
2
frontend/src/components/v2/IconButton/index.tsx
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export type { IconButtonProps } from './IconButton';
|
||||||
|
export { IconButton } from './IconButton';
|
||||||
@@ -13,7 +13,7 @@ type Props = {
|
|||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SelectProps = SelectPrimitive.SelectProps & Props;
|
export type SelectProps = SelectPrimitive.SelectProps & Props;
|
||||||
|
|
||||||
export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
||||||
({ children, placeholder, className, isLoading, ...props }, ref): JSX.Element => {
|
({ children, placeholder, className, isLoading, ...props }, ref): JSX.Element => {
|
||||||
@@ -64,7 +64,7 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
|||||||
|
|
||||||
Select.displayName = 'Select';
|
Select.displayName = 'Select';
|
||||||
|
|
||||||
type SelectItemProps = Omit<SelectPrimitive.SelectItemProps, 'disabled'> & {
|
export type SelectItemProps = Omit<SelectPrimitive.SelectItemProps, 'disabled'> & {
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export {Select} from './Select'
|
export type { SelectItemProps, SelectProps } from './Select';
|
||||||
|
export { Select, SelectItem } from './Select';
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
export * from './Button';
|
export * from './Button';
|
||||||
export * from './FormControl';
|
export * from './FormControl';
|
||||||
|
export * from './IconButton';
|
||||||
export * from './Input';
|
export * from './Input';
|
||||||
|
export * from './Select';
|
||||||
|
|||||||
Reference in New Issue
Block a user