mirror of
https://github.com/acid-info/lsd.git
synced 2025-01-28 01:34:50 +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 = {
|
export const dropdownClasses = {
|
||||||
root: `lsd-dropdown`,
|
root: `lsd-dropdown`,
|
||||||
|
|
||||||
trigger: `lsd-dropdown-trigger`,
|
label: 'lsd-dropdown__label',
|
||||||
triggerLabel: `lsd-dropdown-trigger__label`,
|
buttonContainer: `lsd-dropdown__button-container`,
|
||||||
triggerIcons: `lsd-dropdown-trigger-icons`,
|
|
||||||
triggerIcon: `lsd-dropdown-trigger-icons__icon`,
|
trigger: `lsd-dropdown__trigger`,
|
||||||
triggerMenuIcon: `lsd-dropdown-trigger-icons__menu-icon`,
|
optionLabel: `lsd-dropdown__option-label`,
|
||||||
|
icons: `lsd-dropdown__icons`,
|
||||||
|
icon: `lsd-dropdown__icon`,
|
||||||
|
menuIcon: `lsd-dropdown__menu-icon`,
|
||||||
|
|
||||||
supportingText: 'lsd-dropdown__supporting-text',
|
supportingText: 'lsd-dropdown__supporting-text',
|
||||||
|
|
||||||
listBox: 'lsd-dropdown-list-box',
|
listBox: 'lsd-dropdown__list-box',
|
||||||
|
|
||||||
open: 'lsd-dropdown--open',
|
open: 'lsd-dropdown--open',
|
||||||
error: 'lsd-dropdown--error',
|
error: 'lsd-dropdown--error',
|
||||||
|
@ -12,6 +12,12 @@ export default {
|
|||||||
},
|
},
|
||||||
defaultValue: 'large',
|
defaultValue: 'large',
|
||||||
},
|
},
|
||||||
|
size: {
|
||||||
|
type: {
|
||||||
|
name: 'enum',
|
||||||
|
value: ['small', 'medium', 'large'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as Meta
|
} as Meta
|
||||||
|
|
||||||
@ -22,8 +28,9 @@ export const Root: Story<DropdownProps> = (args) => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
Root.args = {
|
Root.args = {
|
||||||
|
id: 'cryptocurrency',
|
||||||
size: 'large',
|
size: 'large',
|
||||||
label: 'Choose an option',
|
triggerLabel: 'Choose an option',
|
||||||
supportingText: '',
|
supportingText: '',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
error: false,
|
error: false,
|
||||||
@ -34,4 +41,5 @@ Root.args = {
|
|||||||
value: `${index}`,
|
value: `${index}`,
|
||||||
name: `Option ${index + 1}`,
|
name: `Option ${index + 1}`,
|
||||||
})),
|
})),
|
||||||
|
label: 'Cryptocurrency',
|
||||||
}
|
}
|
||||||
|
@ -12,20 +12,28 @@ export const DropdownStyles = css`
|
|||||||
.${dropdownClasses.trigger} {
|
.${dropdownClasses.trigger} {
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
.${dropdownClasses.triggerLabel} {
|
.${dropdownClasses.optionLabel} {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.${dropdownClasses.label} {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${dropdownClasses.buttonContainer} {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.${dropdownClasses.trigger} {
|
.${dropdownClasses.trigger} {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 10px 14px 10px 18px;
|
|
||||||
border: none;
|
border: none;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -36,26 +44,27 @@ export const DropdownStyles = css`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.triggerLabel} {
|
.${dropdownClasses.optionLabel} {
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.triggerIcons} {
|
.${dropdownClasses.icons} {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
min-width: 60px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.triggerIcon} {
|
.${dropdownClasses.icon} {
|
||||||
margin-right: 8px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.triggerMenuIcon} {
|
.${dropdownClasses.menuIcon} {
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.supportingText} {
|
.${dropdownClasses.supportingText} {
|
||||||
@ -63,16 +72,14 @@ export const DropdownStyles = css`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.error} {
|
.${dropdownClasses.error} {
|
||||||
.${dropdownClasses.triggerLabel} {
|
.${dropdownClasses.optionLabel} {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.disabled} {
|
.${dropdownClasses.disabled} {
|
||||||
.${dropdownClasses.trigger} {
|
opacity: 0.34;
|
||||||
opacity: 0.34;
|
cursor: initial;
|
||||||
cursor: initial;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.listBox} {
|
.${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} {
|
.${dropdownClasses.trigger} {
|
||||||
padding: 6px 10px;
|
padding: 9px 17px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.medium} {
|
.${dropdownClasses.medium} {
|
||||||
|
width: 188px;
|
||||||
|
|
||||||
|
.${dropdownClasses.label} {
|
||||||
|
margin: 0 0 6px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${dropdownClasses.buttonContainer} {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.${dropdownClasses.trigger} {
|
.${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} {
|
.${dropdownClasses.outlined} {
|
||||||
border: 1px solid rgb(var(--lsd-border-primary));
|
.${dropdownClasses.buttonContainer} {
|
||||||
|
border: 1px solid rgb(var(--lsd-border-primary));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.${dropdownClasses.outlinedBottom} {
|
.${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>,
|
React.HTMLAttributes<HTMLDivElement>,
|
||||||
'label' | 'disabled' | 'value' | 'onChange'
|
'label' | 'disabled' | 'value' | 'onChange'
|
||||||
> & {
|
> & {
|
||||||
label: string
|
label?: React.ReactNode
|
||||||
error?: boolean
|
error?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
supportingText?: string
|
supportingText?: string
|
||||||
size?: 'small' | 'medium' | 'large'
|
size?: 'small' | 'medium' | 'large'
|
||||||
|
triggerLabel: string
|
||||||
|
|
||||||
multi?: boolean
|
multi?: boolean
|
||||||
options?: DropdownOption[]
|
options?: DropdownOption[]
|
||||||
@ -35,6 +36,7 @@ export const Dropdown: React.FC<DropdownProps> & {
|
|||||||
error = false,
|
error = false,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
supportingText,
|
supportingText,
|
||||||
|
triggerLabel,
|
||||||
|
|
||||||
value = [],
|
value = [],
|
||||||
onChange,
|
onChange,
|
||||||
@ -43,7 +45,7 @@ export const Dropdown: React.FC<DropdownProps> & {
|
|||||||
variant = 'outlined',
|
variant = 'outlined',
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const ref = useRef<HTMLButtonElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
const { select, isSelected, selected } = useSelect(options, value, {
|
const { select, isSelected, selected } = useSelect(options, value, {
|
||||||
@ -62,8 +64,11 @@ export const Dropdown: React.FC<DropdownProps> & {
|
|||||||
if (disabled && open) setOpen(false)
|
if (disabled && open) setOpen(false)
|
||||||
}, [open, disabled])
|
}, [open, disabled])
|
||||||
|
|
||||||
|
const buttonId = props?.id ?? (props.id || 'dropdown') + '-input'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={containerRef}
|
||||||
{...props}
|
{...props}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
props.className,
|
props.className,
|
||||||
@ -72,50 +77,56 @@ export const Dropdown: React.FC<DropdownProps> & {
|
|||||||
error && dropdownClasses.error,
|
error && dropdownClasses.error,
|
||||||
disabled && dropdownClasses.disabled,
|
disabled && dropdownClasses.disabled,
|
||||||
open && dropdownClasses.open,
|
open && dropdownClasses.open,
|
||||||
|
variant === 'outlined'
|
||||||
|
? dropdownClasses.outlined
|
||||||
|
: dropdownClasses.outlinedBottom,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<button
|
{label && (
|
||||||
ref={ref}
|
|
||||||
className={clsx(
|
|
||||||
dropdownClasses.trigger,
|
|
||||||
variant === 'outlined'
|
|
||||||
? dropdownClasses.outlined
|
|
||||||
: dropdownClasses.outlinedBottom,
|
|
||||||
)}
|
|
||||||
onClick={onTrigger}
|
|
||||||
>
|
|
||||||
<Typography
|
<Typography
|
||||||
color="primary"
|
htmlFor={buttonId}
|
||||||
|
className={dropdownClasses.label}
|
||||||
|
variant="label2"
|
||||||
component="label"
|
component="label"
|
||||||
variant={size === 'large' ? 'label1' : 'label2'}
|
|
||||||
className={dropdownClasses.triggerLabel}
|
|
||||||
>
|
>
|
||||||
{selected.length > 0
|
{label}
|
||||||
? selected.map((opt) => opt.name).join(', ')
|
|
||||||
: label}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={dropdownClasses.triggerIcons}>
|
)}
|
||||||
{error && (
|
<div className={dropdownClasses.buttonContainer}>
|
||||||
<ErrorIcon
|
<button
|
||||||
color="primary"
|
id={buttonId}
|
||||||
className={dropdownClasses.triggerIcon}
|
className={clsx(dropdownClasses.trigger)}
|
||||||
/>
|
onClick={onTrigger}
|
||||||
)}
|
>
|
||||||
|
<Typography
|
||||||
{open ? (
|
color="primary"
|
||||||
<ArrowUpIcon
|
component="label"
|
||||||
color="primary"
|
variant={size === 'large' ? 'label1' : 'label2'}
|
||||||
className={dropdownClasses.triggerMenuIcon}
|
className={dropdownClasses.optionLabel}
|
||||||
/>
|
>
|
||||||
) : (
|
{selected.length > 0
|
||||||
<ArrowDownIcon
|
? selected.map((opt) => opt.name).join(', ')
|
||||||
color="primary"
|
: triggerLabel}
|
||||||
className={dropdownClasses.triggerMenuIcon}
|
</Typography>
|
||||||
/>
|
<div className={dropdownClasses.icons}>
|
||||||
)}
|
{error && (
|
||||||
</div>
|
<ErrorIcon color="primary" className={dropdownClasses.icon} />
|
||||||
</button>
|
)}
|
||||||
|
|
||||||
|
{open ? (
|
||||||
|
<ArrowUpIcon
|
||||||
|
color="primary"
|
||||||
|
className={dropdownClasses.menuIcon}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ArrowDownIcon
|
||||||
|
color="primary"
|
||||||
|
className={dropdownClasses.menuIcon}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{supportingText && (
|
{supportingText && (
|
||||||
<Typography
|
<Typography
|
||||||
variant={size === 'large' ? 'label1' : 'label2'}
|
variant={size === 'large' ? 'label1' : 'label2'}
|
||||||
@ -128,7 +139,7 @@ export const Dropdown: React.FC<DropdownProps> & {
|
|||||||
|
|
||||||
<Portal id="dropdown">
|
<Portal id="dropdown">
|
||||||
<ListBox
|
<ListBox
|
||||||
handleRef={ref}
|
handleRef={containerRef}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={() => setOpen(false)}
|
onClose={() => setOpen(false)}
|
||||||
className={dropdownClasses.listBox}
|
className={dropdownClasses.listBox}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user