mirror of https://github.com/buster-so/buster.git
update
This commit is contained in:
parent
49337658ea
commit
e41180ff20
|
@ -4,36 +4,42 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|||
import { cn } from '@/lib/classMerge';
|
||||
import { CircleSpinnerLoader } from '../loaders/CircleSpinnerLoader';
|
||||
|
||||
export const buttonTypeClasses = {
|
||||
default:
|
||||
'bg-white border hover:bg-item-hover disabled:bg-disabled disabled:text-gray-light active:bg-item-active data-[selected=true]:bg-item-select',
|
||||
black: 'bg-black text-white hover:bg-foreground-hover disabled:bg-foreground-hover',
|
||||
primary:
|
||||
'bg-primary text-white hover:bg-primary-light active:bg-primary-dark data-[selected=true]:bg-primary-dark',
|
||||
ghost:
|
||||
'bg-transparent text-gray-dark shadow-none hover:bg-item-hover hover:text-foreground disabled:bg-transparent disabled:text-gray-light active:bg-item-active data-[selected=true]:bg-item-select',
|
||||
link: 'bg-transparent text-gray-dark shadow-none hover:text-foreground disabled:bg-transparent disabled:text-gray-light'
|
||||
};
|
||||
|
||||
const roundingVariants = {
|
||||
default: 'rounded',
|
||||
full: 'rounded-full',
|
||||
large: 'rounded-lg',
|
||||
small: 'rounded-sm',
|
||||
none: 'rounded-none'
|
||||
};
|
||||
|
||||
const sizeVariants = {
|
||||
default: 'h-6',
|
||||
tall: 'h-7',
|
||||
small: 'h-[18px]'
|
||||
};
|
||||
|
||||
export const buttonVariants = cva(
|
||||
'inline-flex items-center overflow-hidden text-base justify-center gap-[5px] shadow-btn rounded transition-all duration-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none cursor-pointer disabled:cursor-not-allowed data-[loading=true]:cursor-progress',
|
||||
{
|
||||
variants: {
|
||||
buttonType: {
|
||||
default:
|
||||
'bg-white border hover:bg-item-hover disabled:bg-disabled disabled:text-gray-light active:bg-item-active data-[selected=true]:bg-item-select',
|
||||
black: 'bg-black text-white hover:bg-foreground-hover disabled:bg-foreground-hover',
|
||||
primary:
|
||||
'bg-primary text-white hover:bg-primary-light active:bg-primary-dark data-[selected=true]:bg-primary-dark',
|
||||
ghost:
|
||||
'bg-transparent text-gray-dark shadow-none hover:bg-item-hover hover:text-foreground disabled:bg-transparent disabled:text-gray-light active:bg-item-active data-[selected=true]:bg-item-select',
|
||||
link: 'bg-transparent text-gray-dark shadow-none hover:text-foreground disabled:bg-transparent disabled:text-gray-light'
|
||||
},
|
||||
size: {
|
||||
default: 'h-6',
|
||||
tall: 'h-7',
|
||||
small: 'h-[18px]'
|
||||
},
|
||||
buttonType: buttonTypeClasses,
|
||||
size: sizeVariants,
|
||||
iconButton: {
|
||||
true: '',
|
||||
false: 'px-2.5'
|
||||
},
|
||||
rounding: {
|
||||
default: 'rounded',
|
||||
full: 'rounded-full',
|
||||
large: 'rounded-lg',
|
||||
small: 'rounded-sm',
|
||||
none: 'rounded-none'
|
||||
}
|
||||
rounding: roundingVariants
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
|
@ -149,7 +155,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|||
|
||||
Button.displayName = 'Button';
|
||||
|
||||
const LoadingIcon: React.FC<{
|
||||
export const LoadingIcon: React.FC<{
|
||||
buttonType: ButtonProps['buttonType'];
|
||||
size: ButtonProps['size'];
|
||||
}> = ({ buttonType = 'default', size = 'default' }) => {
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { ButtonDropdown } from './ButtonDropdown';
|
||||
import { PaintRoller } from '../icons/NucleoIconOutlined';
|
||||
|
||||
const meta: Meta<typeof ButtonDropdown> = {
|
||||
title: 'Base/ButtonDropdown',
|
||||
component: ButtonDropdown,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
argTypes: {
|
||||
buttonType: {
|
||||
control: 'select',
|
||||
options: ['default', 'black', 'primary', 'ghost', 'link']
|
||||
},
|
||||
size: {
|
||||
control: 'select',
|
||||
options: ['default', 'tall', 'small']
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
defaultValue: false
|
||||
},
|
||||
loading: {
|
||||
control: 'boolean',
|
||||
defaultValue: false
|
||||
},
|
||||
rounding: {
|
||||
control: 'select',
|
||||
options: ['default', 'full', 'large', 'small', 'none']
|
||||
}
|
||||
},
|
||||
tags: ['autodocs']
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ButtonDropdown>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
buttonText: 'Button Text',
|
||||
buttonType: 'default'
|
||||
}
|
||||
};
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
buttonText: 'Primary Button',
|
||||
buttonType: 'primary'
|
||||
}
|
||||
};
|
||||
|
||||
export const Black: Story = {
|
||||
args: {
|
||||
buttonText: 'Black Button',
|
||||
buttonType: 'black'
|
||||
}
|
||||
};
|
||||
|
||||
export const Ghost: Story = {
|
||||
args: {
|
||||
buttonText: 'Ghost Button',
|
||||
buttonType: 'ghost'
|
||||
}
|
||||
};
|
||||
|
||||
export const Link: Story = {
|
||||
args: {
|
||||
buttonText: 'Link Button',
|
||||
buttonType: 'link'
|
||||
}
|
||||
};
|
||||
|
||||
export const Tall: Story = {
|
||||
args: {
|
||||
buttonText: 'Tall Button',
|
||||
size: 'tall'
|
||||
}
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
args: {
|
||||
buttonText: 'Small Button',
|
||||
size: 'small'
|
||||
}
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
buttonText: 'Disabled Button',
|
||||
disabled: true
|
||||
}
|
||||
};
|
||||
|
||||
export const WithIcon: Story = {
|
||||
args: {
|
||||
buttonText: 'With Icon',
|
||||
icon: <PaintRoller />
|
||||
}
|
||||
};
|
|
@ -1,5 +1,119 @@
|
|||
import React from 'react';
|
||||
import { buttonVariants, buttonIconVariants } from './Button';
|
||||
import { ChevronDown, ChevronUp } from '../icons/NucleoIconOutlined';
|
||||
import {
|
||||
buttonVariants,
|
||||
buttonIconVariants,
|
||||
ButtonProps,
|
||||
buttonTypeClasses,
|
||||
LoadingIcon
|
||||
} from './Button';
|
||||
import { ChevronDown } from '../icons/NucleoIconOutlined';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import { type DropdownProps, Dropdown } from '../dropdown/Dropdown';
|
||||
|
||||
interface ButtonDropdownProps {
|
||||
icon?: React.ReactNode;
|
||||
buttonText?: string;
|
||||
disabled?: boolean;
|
||||
rounding?: ButtonProps['rounding'];
|
||||
size?: ButtonProps['size'];
|
||||
buttonType?: ButtonProps['buttonType'];
|
||||
loading?: boolean;
|
||||
className?: string;
|
||||
iconClassName?: string;
|
||||
dropdownProps: Omit<DropdownProps, 'children'>;
|
||||
}
|
||||
|
||||
const dropdownButtonVariants = cva('flex items-center pr-0', {
|
||||
variants: {
|
||||
rounding: {
|
||||
default: 'rounded',
|
||||
full: 'rounded-full',
|
||||
large: 'rounded-lg',
|
||||
small: 'rounded-sm',
|
||||
none: 'rounded-none'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const primaryButtonVariants = cva('', {
|
||||
variants: {
|
||||
buttonType: buttonTypeClasses
|
||||
}
|
||||
});
|
||||
|
||||
const splitButtonVariants = cva('flex w-full items-center justify-center h-full px-[5px]', {
|
||||
variants: {
|
||||
buttonType: buttonTypeClasses
|
||||
}
|
||||
});
|
||||
|
||||
export const ButtonDropdown = React.forwardRef<HTMLDivElement, ButtonDropdownProps>(
|
||||
({ dropdownProps, ...buttonProps }, ref) => {
|
||||
return (
|
||||
<Dropdown {...dropdownProps}>
|
||||
<ButtonSplit ref={ref} {...buttonProps} />
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const ButtonSplit = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
Omit<ButtonDropdownProps, 'dropdownProps'>
|
||||
>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
buttonType = 'default',
|
||||
size = 'default',
|
||||
icon,
|
||||
buttonText,
|
||||
disabled = false,
|
||||
rounding = 'default',
|
||||
loading = false,
|
||||
iconClassName
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
buttonVariants({ buttonType, size, rounding: 'none' }),
|
||||
dropdownButtonVariants({ rounding }),
|
||||
'gap-0 !bg-transparent p-0',
|
||||
disabled && 'cursor-not-allowed opacity-60',
|
||||
className
|
||||
)}>
|
||||
<div
|
||||
className={cn(
|
||||
primaryButtonVariants({ buttonType }),
|
||||
'flex h-full items-center gap-0.5 border-none pr-2 pl-2.5'
|
||||
)}>
|
||||
{loading ? (
|
||||
<LoadingIcon buttonType={buttonType} size={size} />
|
||||
) : (
|
||||
icon && (
|
||||
<span
|
||||
className={cn(buttonIconVariants({ buttonType, size }), 'text-sm', iconClassName)}>
|
||||
{icon}
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
{buttonText && <span className="">{buttonText}</span>}
|
||||
</div>
|
||||
<div className="bg-border mr-0 h-full w-[0.5px]" />
|
||||
<div className="flex h-full items-center justify-center text-sm">
|
||||
<div
|
||||
className={cn(splitButtonVariants({ buttonType }), 'border-none')}
|
||||
aria-label="Open dropdown menu">
|
||||
<ChevronDown />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
ButtonSplit.displayName = 'ButtonSplit';
|
||||
|
|
Loading…
Reference in New Issue