feat: add label element to Dropdown component and adjust styles

This commit is contained in:
jinhojang6 2023-04-07 20:57:14 +09:00
parent 3369e8aaf2
commit 0a98af2441
4 changed files with 125 additions and 59 deletions

View File

@ -1,15 +1,18 @@
export const dropdownClasses = {
root: `lsd-dropdown`,
trigger: `lsd-dropdown-trigger`,
triggerLabel: `lsd-dropdown-trigger__label`,
triggerIcons: `lsd-dropdown-trigger-icons`,
triggerIcon: `lsd-dropdown-trigger-icons__icon`,
triggerMenuIcon: `lsd-dropdown-trigger-icons__menu-icon`,
label: 'lsd-dropdown__label',
buttonContainer: `lsd-dropdown__button-container`,
trigger: `lsd-dropdown__trigger`,
triggerLabel: `lsd-dropdown__trigger-label`,
triggerIcons: `lsd-dropdown__trigger-icons`,
triggerIcon: `lsd-dropdown__trigger-icons__icon`,
triggerMenuIcon: `lsd-dropdown__trigger-icons__menu-icon`,
supportingText: 'lsd-dropdown__supporting-text',
listBox: 'lsd-dropdown-list-box',
listBox: 'lsd-dropdown__list-box',
open: 'lsd-dropdown--open',
error: 'lsd-dropdown--error',

View File

@ -22,8 +22,9 @@ export const Root: Story<DropdownProps> = (args) => (
)
Root.args = {
id: 'cryptocurrency',
size: 'large',
label: 'Choose an option',
triggerLabel: 'Choose an option',
supportingText: '',
disabled: false,
error: false,
@ -34,4 +35,5 @@ Root.args = {
value: `${index}`,
name: `Option ${index + 1}`,
})),
label: 'Cryptocurrency',
}

View File

@ -19,13 +19,21 @@ export const DropdownStyles = css`
}
}
.${dropdownClasses.label} {
display: block;
}
.${dropdownClasses.buttonContainer} {
display: flex;
justify-content: space-between;
}
.${dropdownClasses.trigger} {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 10px 14px 10px 18px;
border: none;
cursor: pointer;
@ -48,11 +56,12 @@ export const DropdownStyles = css`
flex-direction: row;
align-items: center;
justify-content: flex-end;
min-width: 60px;
gap: 8px;
}
.${dropdownClasses.triggerIcon} {
margin-right: 8px;
display: flex;
align-items: center;
}
.${dropdownClasses.triggerMenuIcon} {
@ -69,10 +78,8 @@ export const DropdownStyles = css`
}
.${dropdownClasses.disabled} {
.${dropdownClasses.trigger} {
opacity: 0.34;
cursor: initial;
}
opacity: 0.34;
cursor: initial;
}
.${dropdownClasses.listBox} {
@ -90,23 +97,63 @@ export const DropdownStyles = css`
}
}
.${dropdownClasses.small} {
.${dropdownClasses.large} {
width: 208px;
.${dropdownClasses.label} {
margin: 0 0 6px 18px;
}
.${dropdownClasses.buttonContainer} {
height: 40px;
}
.${dropdownClasses.trigger} {
padding: 6px 10px;
padding: 9px 17px;
}
}
.${dropdownClasses.medium} {
width: 188px;
.${dropdownClasses.label} {
margin: 0 0 6px 14px;
}
.${dropdownClasses.buttonContainer} {
height: 32px;
}
.${dropdownClasses.trigger} {
padding: 6px 12px;
padding: 5px 13px;
}
}
.${dropdownClasses.small} {
width: 164px;
.${dropdownClasses.label} {
margin: 0 0 6px 12px;
}
.${dropdownClasses.buttonContainer} {
height: 28px;
}
.${dropdownClasses.trigger} {
padding: 5px 11px;
}
}
.${dropdownClasses.outlined} {
border: 1px solid rgb(var(--lsd-border-primary));
.${dropdownClasses.buttonContainer} {
border: 1px solid rgb(var(--lsd-border-primary));
}
}
.${dropdownClasses.outlinedBottom} {
border-bottom: 1px solid rgb(var(--lsd-border-primary));
.${dropdownClasses.buttonContainer} {
border-bottom: 1px solid rgb(var(--lsd-border-primary));
}
}
`

View File

@ -14,11 +14,12 @@ export type DropdownProps = Omit<
React.HTMLAttributes<HTMLDivElement>,
'label' | 'disabled' | 'value' | 'onChange'
> & {
label: string
label?: React.ReactNode
error?: boolean
disabled?: boolean
supportingText?: string
size?: 'small' | 'medium' | 'large'
triggerLabel: string
multi?: boolean
options?: DropdownOption[]
@ -35,6 +36,7 @@ export const Dropdown: React.FC<DropdownProps> & {
error = false,
disabled = false,
supportingText,
triggerLabel,
value = [],
onChange,
@ -43,7 +45,7 @@ export const Dropdown: React.FC<DropdownProps> & {
variant = 'outlined',
...props
}) => {
const ref = useRef<HTMLButtonElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
const [open, setOpen] = useState(false)
const { select, isSelected, selected } = useSelect(options, value, {
@ -62,8 +64,11 @@ export const Dropdown: React.FC<DropdownProps> & {
if (disabled && open) setOpen(false)
}, [open, disabled])
const buttonId = props?.id ?? (props.id || 'dropdown') + '-input'
return (
<div
ref={containerRef}
{...props}
className={clsx(
props.className,
@ -72,50 +77,59 @@ export const Dropdown: React.FC<DropdownProps> & {
error && dropdownClasses.error,
disabled && dropdownClasses.disabled,
open && dropdownClasses.open,
variant === 'outlined'
? dropdownClasses.outlined
: dropdownClasses.outlinedBottom,
)}
>
<button
ref={ref}
className={clsx(
dropdownClasses.trigger,
variant === 'outlined'
? dropdownClasses.outlined
: dropdownClasses.outlinedBottom,
)}
onClick={onTrigger}
>
{label && (
<Typography
color="primary"
htmlFor={buttonId}
className={dropdownClasses.label}
variant="label2"
component="label"
variant={size === 'large' ? 'label1' : 'label2'}
className={dropdownClasses.triggerLabel}
>
{selected.length > 0
? selected.map((opt) => opt.name).join(', ')
: label}
{label}
</Typography>
<div className={dropdownClasses.triggerIcons}>
{error && (
<ErrorIcon
color="primary"
className={dropdownClasses.triggerIcon}
/>
)}
{open ? (
<ArrowUpIcon
color="primary"
className={dropdownClasses.triggerMenuIcon}
/>
) : (
<ArrowDownIcon
color="primary"
className={dropdownClasses.triggerMenuIcon}
/>
)}
</div>
</button>
)}
<div className={dropdownClasses.buttonContainer}>
<button
id={buttonId}
className={clsx(dropdownClasses.trigger)}
onClick={onTrigger}
>
<Typography
color="primary"
component="label"
variant={size === 'large' ? 'label1' : 'label2'}
className={dropdownClasses.triggerLabel}
>
{selected.length > 0
? selected.map((opt) => opt.name).join(', ')
: triggerLabel}
</Typography>
<div className={dropdownClasses.triggerIcons}>
{error && (
<ErrorIcon
color="primary"
className={dropdownClasses.triggerIcon}
/>
)}
{open ? (
<ArrowUpIcon
color="primary"
className={dropdownClasses.triggerMenuIcon}
/>
) : (
<ArrowDownIcon
color="primary"
className={dropdownClasses.triggerMenuIcon}
/>
)}
</div>
</button>
</div>
{supportingText && (
<Typography
variant={size === 'large' ? 'label1' : 'label2'}
@ -128,7 +142,7 @@ export const Dropdown: React.FC<DropdownProps> & {
<Portal id="dropdown">
<ListBox
handleRef={ref}
handleRef={containerRef}
open={open}
onClose={() => setOpen(false)}
className={dropdownClasses.listBox}