mirror of
https://github.com/acid-info/lsd.git
synced 2025-01-27 01:09:59 +00:00
Merge pull request #30 from acid-info/topic-update-dropdown
Update Dropdown component
This commit is contained in:
commit
e1e280ef00
@ -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',
|
||||
|
@ -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',
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -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}
|
||||
|
Loading…
x
Reference in New Issue
Block a user