|
|
@@ -53,11 +53,42 @@ export interface MenuMultiSelectProps extends Omit<React.HTMLProps<MenuMultiSele |
|
|
|
* Starting height of the component. |
|
|
|
*/ |
|
|
|
startingHeight?: number | string, |
|
|
|
/** |
|
|
|
* Should the component be resizable? |
|
|
|
*/ |
|
|
|
resizable?: boolean, |
|
|
|
} |
|
|
|
|
|
|
|
export const menuMultiSelectPlugin: tailwind.PluginCreator = ({ addComponents }) => { |
|
|
|
addComponents({ |
|
|
|
'.menu-multi-select': { |
|
|
|
'&[data-variant="alternate"][data-size="small"]': { |
|
|
|
'--td-padding-top': '1.25rem', |
|
|
|
}, |
|
|
|
'&[data-variant="alternate"][data-size="medium"]': { |
|
|
|
'--td-padding-top': '1.5rem', |
|
|
|
}, |
|
|
|
'&[data-variant="alternate"][data-size="large"]': { |
|
|
|
'--td-padding-top': '2rem', |
|
|
|
}, |
|
|
|
'&[data-variant="default"][data-size="small"]': { |
|
|
|
'--td-padding-top': '0.625rem', |
|
|
|
'--td-padding-bottom': '0.625rem', |
|
|
|
}, |
|
|
|
'&[data-variant="default"][data-size="medium"]': { |
|
|
|
'--td-padding-top': '0.75rem', |
|
|
|
'--td-padding-bottom': '0.75rem', |
|
|
|
}, |
|
|
|
'&[data-variant="default"][data-size="large"]': { |
|
|
|
'--td-padding-top': '1.25rem', |
|
|
|
'--td-padding-bottom': '1.25rem', |
|
|
|
}, |
|
|
|
'padding-top': 'var(--td-padding-top, 0)', |
|
|
|
'padding-bottom': 'var(--td-padding-bottom, 0)', |
|
|
|
'scrollbar-width': '0', |
|
|
|
'&::-webkit-scrollbar': { |
|
|
|
'display': 'none', |
|
|
|
}, |
|
|
|
'& optgroup': { |
|
|
|
'color': 'rgb(var(--color-positive) / 50%)', |
|
|
|
'text-transform': 'uppercase', |
|
|
@@ -99,6 +130,7 @@ export const MenuMultiSelect = React.forwardRef< |
|
|
|
startingHeight = '15rem', |
|
|
|
id: idProp, |
|
|
|
style, |
|
|
|
resizable = false as const, |
|
|
|
...etcProps |
|
|
|
}, |
|
|
|
forwardedRef, |
|
|
@@ -109,7 +141,7 @@ export const MenuMultiSelect = React.forwardRef< |
|
|
|
return ( |
|
|
|
<div |
|
|
|
className={tw( |
|
|
|
'menu-multi-select relative rounded ring-secondary/50 group has-[:disabled]:opacity-50', |
|
|
|
'bg-negative relative rounded ring-secondary/50 group has-[:disabled]:opacity-50', |
|
|
|
'focus-within:ring-4', |
|
|
|
{ |
|
|
|
'block': block, |
|
|
@@ -120,139 +152,137 @@ export const MenuMultiSelect = React.forwardRef< |
|
|
|
data-testid="base" |
|
|
|
style={style} |
|
|
|
> |
|
|
|
{label && ( |
|
|
|
<> |
|
|
|
<label |
|
|
|
data-testid="label" |
|
|
|
id={labelId} |
|
|
|
htmlFor={id} |
|
|
|
className={tw( |
|
|
|
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold group-focus-within:text-secondary text-primary leading-none bg-negative select-none', |
|
|
|
{ |
|
|
|
'sr-only': hiddenLabel, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-1': !indicator, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-10': indicator && size === 'small', |
|
|
|
'pr-12': indicator && size === 'medium', |
|
|
|
'pr-16': indicator && size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
> |
|
|
|
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> |
|
|
|
{label} |
|
|
|
</span> |
|
|
|
</label> |
|
|
|
{' '} |
|
|
|
</> |
|
|
|
)} |
|
|
|
<MenuMultiSelectDerivedElementComponent |
|
|
|
{...etcProps} |
|
|
|
ref={forwardedRef} |
|
|
|
id={id} |
|
|
|
aria-labelledby={labelId} |
|
|
|
data-testid="input" |
|
|
|
size={2} |
|
|
|
multiple |
|
|
|
style={{ |
|
|
|
height: startingHeight, |
|
|
|
}} |
|
|
|
className={tw( |
|
|
|
'bg-negative rounded-inherit w-full peer block overflow-auto font-inherit cursor-pointer', |
|
|
|
'focus:outline-0', |
|
|
|
'disabled:opacity-50 disabled:cursor-not-allowed', |
|
|
|
{ |
|
|
|
'resize': !block, |
|
|
|
'resize-y': block, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'text-xxs': size === 'small', |
|
|
|
'text-xs': size === 'medium', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pl-4': variant === 'default', |
|
|
|
'pl-1.5': variant === 'alternate', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pt-4': variant === 'alternate' && size === 'small', |
|
|
|
'pt-5': variant === 'alternate' && size === 'medium', |
|
|
|
'pt-8': variant === 'alternate' && size === 'large', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'py-2.5': variant === 'default' && size === 'small', |
|
|
|
'py-3': variant === 'default' && size === 'medium', |
|
|
|
'py-5': variant === 'default' && size === 'large', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-4': variant === 'default' && !indicator, |
|
|
|
'pr-1.5': variant === 'alternate' && !indicator, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-10': indicator && size === 'small', |
|
|
|
'pr-12': indicator && size === 'medium', |
|
|
|
'pr-16': indicator && size === 'large', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'min-h-10': size === 'small', |
|
|
|
'min-h-12': size === 'medium', |
|
|
|
'min-h-16': size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
/> |
|
|
|
{hint && ( |
|
|
|
<div |
|
|
|
data-testid="hint" |
|
|
|
className={tw( |
|
|
|
'absolute left-0 px-1 pointer-events-none text-xxs leading-none w-full bg-negative select-none', |
|
|
|
{ |
|
|
|
'bottom-0 pl-4 pb-1': variant === 'default', |
|
|
|
'top-0.5': variant === 'alternate', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pt-2': variant === 'alternate' && size === 'small', |
|
|
|
'pt-3': variant === 'alternate' && size !== 'small', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-4': !indicator && variant === 'default', |
|
|
|
'pr-1': !indicator && variant === 'alternate', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-10': indicator && size === 'small', |
|
|
|
'pr-12': indicator && size === 'medium', |
|
|
|
'pr-16': indicator && size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
> |
|
|
|
<div |
|
|
|
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis" |
|
|
|
> |
|
|
|
{hint} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
{indicator && ( |
|
|
|
<div |
|
|
|
data-testid="indicator" |
|
|
|
className={tw( |
|
|
|
'text-center flex items-center justify-center aspect-square absolute bottom-0 right-0 pointer-events-none select-none', |
|
|
|
{ |
|
|
|
'w-10': size === 'small', |
|
|
|
'w-12': size === 'medium', |
|
|
|
'w-16': size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
> |
|
|
|
{indicator} |
|
|
|
</div> |
|
|
|
)} |
|
|
|
{border && ( |
|
|
|
<span |
|
|
|
data-testid="border" |
|
|
|
className="absolute z-[1] inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary" |
|
|
|
/> |
|
|
|
)} |
|
|
|
<div |
|
|
|
className={tw( |
|
|
|
'w-full overflow-hidden min-h-16 relative min-h-16 rounded-inherit', |
|
|
|
{ |
|
|
|
'resize': !block && resizable, |
|
|
|
'resize-y': block && resizable, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'min-h-10': size === 'small', |
|
|
|
'min-h-12': size === 'medium', |
|
|
|
'min-h-16': size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
style={{ |
|
|
|
height: startingHeight, |
|
|
|
}} |
|
|
|
> |
|
|
|
{label && ( |
|
|
|
<> |
|
|
|
<label |
|
|
|
data-testid="label" |
|
|
|
id={labelId} |
|
|
|
htmlFor={id} |
|
|
|
className={tw( |
|
|
|
'bg-negative absolute z-[1] w-full top-0 pt-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold group-focus-within:text-secondary text-primary leading-none select-none', |
|
|
|
{ |
|
|
|
'sr-only': hiddenLabel, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-1': !indicator, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-10': indicator && size === 'small', |
|
|
|
'pr-12': indicator && size === 'medium', |
|
|
|
'pr-16': indicator && size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
> |
|
|
|
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> |
|
|
|
{label} |
|
|
|
</span> |
|
|
|
</label> |
|
|
|
{' '} |
|
|
|
</> |
|
|
|
)} |
|
|
|
<MenuMultiSelectDerivedElementComponent |
|
|
|
{...etcProps} |
|
|
|
ref={forwardedRef} |
|
|
|
id={id} |
|
|
|
aria-labelledby={labelId} |
|
|
|
data-testid="input" |
|
|
|
size={2} |
|
|
|
multiple |
|
|
|
data-variant={variant} |
|
|
|
data-size={size} |
|
|
|
className={tw( |
|
|
|
'menu-multi-select bg-negative rounded-inherit w-full h-full peer block overflow-auto cursor-pointer font-inherit', |
|
|
|
'focus:outline-0', |
|
|
|
'disabled:opacity-50 disabled:cursor-not-allowed', |
|
|
|
{ |
|
|
|
'text-xxs': size === 'small', |
|
|
|
'text-xs': size === 'medium', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pl-4': variant === 'default', |
|
|
|
'pl-1.5': variant === 'alternate', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-4': variant === 'default' && !indicator, |
|
|
|
'pr-1.5': variant === 'alternate' && !indicator, |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-10': indicator && size === 'small', |
|
|
|
'pr-12': indicator && size === 'medium', |
|
|
|
'pr-16': indicator && size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
/> |
|
|
|
{hint && ( |
|
|
|
<div |
|
|
|
data-testid="hint" |
|
|
|
className={tw( |
|
|
|
'bg-negative absolute left-0 px-1 pointer-events-none text-xxs leading-none w-full select-none', |
|
|
|
{ |
|
|
|
'bottom-0 pl-4 pb-1': variant === 'default', |
|
|
|
'top-0.5': variant === 'alternate', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pt-2': variant === 'alternate' && size === 'small', |
|
|
|
'pt-3': variant === 'alternate' && size !== 'small', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-4': !indicator && variant === 'default', |
|
|
|
'pr-1': !indicator && variant === 'alternate', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'pr-10': indicator && size === 'small', |
|
|
|
'pr-12': indicator && size === 'medium', |
|
|
|
'pr-16': indicator && size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
> |
|
|
|
<div |
|
|
|
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis" |
|
|
|
> |
|
|
|
{hint} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
{indicator && ( |
|
|
|
<div |
|
|
|
data-testid="indicator" |
|
|
|
className={tw( |
|
|
|
'text-center flex items-center justify-center aspect-square absolute bottom-0 right-0 pointer-events-none select-none', |
|
|
|
{ |
|
|
|
'w-10': size === 'small', |
|
|
|
'w-12': size === 'medium', |
|
|
|
'w-16': size === 'large', |
|
|
|
}, |
|
|
|
)} |
|
|
|
> |
|
|
|
{indicator} |
|
|
|
</div> |
|
|
|
)} |
|
|
|
{border && ( |
|
|
|
<span |
|
|
|
data-testid="border" |
|
|
|
className="absolute z-[1] inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary" |
|
|
|
/> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
}); |
|
|
@@ -263,10 +293,11 @@ MenuMultiSelect.defaultProps = { |
|
|
|
label: undefined, |
|
|
|
hint: undefined, |
|
|
|
indicator: undefined, |
|
|
|
size: 'medium', |
|
|
|
border: false, |
|
|
|
block: false, |
|
|
|
variant: 'default', |
|
|
|
hiddenLabel: false, |
|
|
|
startingHeight: '15rem', |
|
|
|
size: 'medium' as const, |
|
|
|
border: false as const, |
|
|
|
block: false as const, |
|
|
|
variant: 'default' as const, |
|
|
|
hiddenLabel: false as const, |
|
|
|
startingHeight: '15rem' as const, |
|
|
|
resizable: false as const, |
|
|
|
}; |