Merge pull request #30 from acid-info/topic-update-dropdown

Update Dropdown component
This commit is contained in:
jeangovil 2023-04-11 01:43:02 +03:30 committed by GitHub
commit e1e280ef00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 134 additions and 65 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`,
optionLabel: `lsd-dropdown__option-label`,
icons: `lsd-dropdown__icons`,
icon: `lsd-dropdown__icon`,
menuIcon: `lsd-dropdown__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

@ -12,6 +12,12 @@ export default {
},
defaultValue: 'large',
},
size: {
type: {
name: 'enum',
value: ['small', 'medium', 'large'],
},
},
},
} as Meta
@ -22,8 +28,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 +41,5 @@ Root.args = {
value: `${index}`,
name: `Option ${index + 1}`,
})),
label: 'Cryptocurrency',
}

View File

@ -12,20 +12,28 @@ export const DropdownStyles = css`
.${dropdownClasses.trigger} {
&:hover,
&:focus {
.${dropdownClasses.triggerLabel} {
.${dropdownClasses.optionLabel} {
text-decoration: underline;
}
}
}
}
.${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;
@ -36,26 +44,27 @@ export const DropdownStyles = css`
}
}
.${dropdownClasses.triggerLabel} {
.${dropdownClasses.optionLabel} {
cursor: inherit;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.${dropdownClasses.triggerIcons} {
.${dropdownClasses.icons} {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
min-width: 60px;
gap: 8px;
}
.${dropdownClasses.triggerIcon} {
margin-right: 8px;
.${dropdownClasses.icon} {
display: flex;
align-items: center;
}
.${dropdownClasses.triggerMenuIcon} {
.${dropdownClasses.menuIcon} {
}
.${dropdownClasses.supportingText} {
@ -63,16 +72,14 @@ export const DropdownStyles = css`
}
.${dropdownClasses.error} {
.${dropdownClasses.triggerLabel} {
.${dropdownClasses.optionLabel} {
text-decoration: line-through;
}
}
.${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,56 @@ 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.optionLabel}
>
{selected.length > 0
? selected.map((opt) => opt.name).join(', ')
: triggerLabel}
</Typography>
<div className={dropdownClasses.icons}>
{error && (
<ErrorIcon color="primary" className={dropdownClasses.icon} />
)}
{open ? (
<ArrowUpIcon
color="primary"
className={dropdownClasses.menuIcon}
/>
) : (
<ArrowDownIcon
color="primary"
className={dropdownClasses.menuIcon}
/>
)}
</div>
</button>
</div>
{supportingText && (
<Typography
variant={size === 'large' ? 'label1' : 'label2'}
@ -128,7 +139,7 @@ export const Dropdown: React.FC<DropdownProps> & {
<Portal id="dropdown">
<ListBox
handleRef={ref}
handleRef={containerRef}
open={open}
onClose={() => setOpen(false)}
className={dropdownClasses.listBox}