import styled from '@emotion/styled';
import type { CSSProperties, ForwardedRef, SelectHTMLAttributes } from 'react';
import { useCallback } from 'react';
import { forwardRefWithGeneric } from '../utility/forwardRef.js';
const arrowDownIcon = `url('data:image/svg+xml;utf8,')`;
const BaseSelect = styled.select<{ width: number | string | undefined }>`
align-self: center;
appearance: none;
background: ${arrowDownIcon} no-repeat right white;
background-position-x: calc(100% - 5px);
background-size: 15px 15px;
border: 0.55px solid #cacaca;
border-radius: 5px;
font-size: 14px;
height: 100%;
margin: 0;
padding: 0 5px;
width: ${({ width }) => (width ? Number(width) - 5 : 115)}px;
:focus,
input:focus {
outline: none;
}
:required:invalid {
color: #666;
}
`;
interface SelectProps extends Omit<
SelectHTMLAttributes,
'style' | 'onChange'
> {
onChange?: (element: string) => void;
items: T[];
defaultValue?: string | number | undefined;
style?: CSSProperties;
placeholder?: string;
itemValueField?: keyof T;
itemTextField?: keyof T;
returnValue?: boolean;
textRender?: (text: string) => string;
}
const Select = forwardRefWithGeneric(function Select(
props: SelectProps,
ref: ForwardedRef,
) {
const {
items,
style = { width: 100 },
onChange = () => null,
defaultValue,
value,
name = '',
className = '',
placeholder = '',
itemValueField = 'value' as keyof T,
itemTextField = 'label' as keyof T,
returnValue = true,
textRender,
...otherProps
} = props;
const handleOnChanged = useCallback(
(e: any) => {
const [option] = e.target.selectedOptions;
const selectedData = JSON.parse(option.dataset.value);
onChange(returnValue ? selectedData[itemValueField] : selectedData);
},
[itemValueField, onChange, returnValue],
);
return (
{placeholder && (
)}
{items.map((option) => {
const value = option[itemValueField];
if (!['number', 'string'].includes(typeof option[itemTextField])) {
// eslint-disable-next-line no-console
console.log(
`The '${String(itemTextField)}' field should be a string or number, option : ${JSON.stringify(
option,
)}`,
);
return null;
}
if (!['number', 'string'].includes(typeof value)) {
// eslint-disable-next-line no-console
console.log(
`The '${String(itemValueField)}' field should be either a string or a number, option : ${JSON.stringify(
option,
)}`,
);
return null;
}
const label = String(option[itemTextField]);
return (
);
})}
);
});
export default Select;