ConceptPortal-public/rsconcept/frontend/src/components/ui/Input/SelectSingle.tsx

126 lines
3.5 KiB
TypeScript
Raw Normal View History

'use client';
2024-04-22 12:33:22 +03:00
import Select, {
ClearIndicatorProps,
components,
DropdownIndicatorProps,
GroupBase,
Props,
StylesConfig
} from 'react-select';
2025-01-28 23:23:42 +03:00
import { IconClose, IconDropArrow, IconDropArrowUp } from '@/components/Icons';
2024-04-22 12:33:22 +03:00
import useWindowSize from '@/hooks/useWindowSize';
import { APP_COLORS, SELECT_THEME } from '@/styling/color';
2024-04-22 12:33:22 +03:00
function DropdownIndicator<Option, Group extends GroupBase<Option> = GroupBase<Option>>(
props: DropdownIndicatorProps<Option, false, Group>
) {
return (
components.DropdownIndicator && (
<components.DropdownIndicator {...props}>
2024-05-11 20:53:36 +03:00
{props.selectProps.menuIsOpen ? <IconDropArrowUp size='1.25rem' /> : <IconDropArrow size='1.25rem' />}
2024-04-22 12:33:22 +03:00
</components.DropdownIndicator>
)
);
}
function ClearIndicator<Option, Group extends GroupBase<Option> = GroupBase<Option>>(
props: ClearIndicatorProps<Option, false, Group>
) {
return (
components.ClearIndicator && (
<components.ClearIndicator {...props}>
<IconClose size='1.25rem' />
</components.ClearIndicator>
)
);
}
export interface SelectSingleProps<Option, Group extends GroupBase<Option> = GroupBase<Option>>
2023-12-28 14:04:44 +03:00
extends Omit<Props<Option, false, Group>, 'theme' | 'menuPortalTarget'> {
noPortal?: boolean;
2024-04-07 19:22:19 +03:00
noBorder?: boolean;
}
/**
* Displays a single-select component.
*/
2025-02-07 10:54:47 +03:00
export function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
2023-12-28 14:04:44 +03:00
noPortal,
2024-04-07 19:22:19 +03:00
noBorder,
2023-12-28 14:04:44 +03:00
...restProps
2023-11-29 13:07:55 +03:00
}: SelectSingleProps<Option, Group>) {
2024-04-22 12:33:22 +03:00
const size = useWindowSize();
const adjustedStyles: StylesConfig<Option, false, Group> = {
container: defaultStyles => ({
...defaultStyles,
borderRadius: '0.25rem'
}),
control: (defaultStyles, { isDisabled }) => ({
...defaultStyles,
borderRadius: '0.25rem',
...(noBorder ? { borderWidth: 0 } : {}),
cursor: isDisabled ? 'not-allowed' : 'pointer',
boxShadow: 'none'
}),
menuPortal: defaultStyles => ({
...defaultStyles,
zIndex: 9999
}),
menuList: defaultStyles => ({
...defaultStyles,
padding: 0
}),
option: (defaultStyles, { isSelected }) => ({
...defaultStyles,
padding: '0.25rem 0.75rem',
fontSize: '0.875rem',
lineHeight: '1.25rem',
backgroundColor: isSelected ? APP_COLORS.bgSelected : defaultStyles.backgroundColor,
color: isSelected ? APP_COLORS.fgSelected : defaultStyles.color,
borderWidth: '1px',
borderColor: APP_COLORS.border
}),
input: defaultStyles => ({ ...defaultStyles }),
placeholder: defaultStyles => ({ ...defaultStyles }),
singleValue: defaultStyles => ({ ...defaultStyles }),
dropdownIndicator: base => ({
...base,
paddingTop: 0,
paddingBottom: 0
}),
clearIndicator: base => ({
...base,
paddingTop: 0,
paddingBottom: 0
})
};
return (
2023-12-28 14:04:44 +03:00
<Select
noOptionsMessage={() => 'Список пуст'}
2024-04-22 12:33:22 +03:00
components={{ DropdownIndicator, ClearIndicator }}
2023-12-28 14:04:44 +03:00
theme={theme => ({
...theme,
borderRadius: 0,
2024-04-22 12:33:22 +03:00
spacing: {
...theme.spacing, // prettier: split-lines
baseUnit: size.isSmall ? 2 : 4,
2024-09-21 20:04:07 +03:00
menuGutter: 2,
2024-04-22 12:33:22 +03:00
controlHeight: size.isSmall ? 28 : 38
},
2023-12-28 14:04:44 +03:00
colors: {
...theme.colors,
...SELECT_THEME
2023-12-28 14:04:44 +03:00
}
})}
menuPortalTarget={!noPortal ? document.body : null}
styles={adjustedStyles}
2024-05-12 13:58:28 +03:00
classNames={{ container: () => 'focus-frame' }}
2023-12-28 14:04:44 +03:00
{...restProps}
/>
);
}