2022-07-14 12:40:53 +00:00
|
|
|
import React, { useCallback, useEffect, useState } from "react";
|
|
|
|
import ReactSelect, { components, GroupBase, Props, InputProps, SingleValue, MultiValue } from "react-select";
|
2021-09-22 19:52:38 +00:00
|
|
|
|
2021-09-14 08:45:28 +00:00
|
|
|
import classNames from "@lib/classNames";
|
|
|
|
|
2022-04-14 14:58:23 +00:00
|
|
|
export type SelectProps<
|
|
|
|
Option,
|
|
|
|
IsMulti extends boolean = false,
|
|
|
|
Group extends GroupBase<Option> = GroupBase<Option>
|
|
|
|
> = Props<Option, IsMulti, Group>;
|
|
|
|
|
|
|
|
export const InputComponent = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>({
|
|
|
|
inputClassName,
|
|
|
|
...props
|
|
|
|
}: InputProps<Option, IsMulti, Group>) => {
|
|
|
|
return (
|
|
|
|
<components.Input
|
|
|
|
// disables our default form focus hightlight on the react-select input element
|
|
|
|
inputClassName={classNames("focus:ring-0 focus:ring-offset-0", inputClassName)}
|
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-11-10 11:16:32 +00:00
|
|
|
function Select<
|
|
|
|
Option,
|
|
|
|
IsMulti extends boolean = false,
|
|
|
|
Group extends GroupBase<Option> = GroupBase<Option>
|
2022-04-14 14:58:23 +00:00
|
|
|
>({ className, ...props }: SelectProps<Option, IsMulti, Group>) {
|
2021-11-10 11:16:32 +00:00
|
|
|
return (
|
|
|
|
<ReactSelect
|
|
|
|
theme={(theme) => ({
|
|
|
|
...theme,
|
|
|
|
borderRadius: 2,
|
|
|
|
colors: {
|
|
|
|
...theme.colors,
|
2022-04-14 14:58:23 +00:00
|
|
|
primary: "var(--brand-color)",
|
2022-03-22 10:34:36 +00:00
|
|
|
|
|
|
|
primary50: "rgba(209 , 213, 219, var(--tw-bg-opacity))",
|
2021-11-10 11:16:32 +00:00
|
|
|
primary25: "rgba(244, 245, 246, var(--tw-bg-opacity))",
|
|
|
|
},
|
|
|
|
})}
|
2022-03-18 18:31:30 +00:00
|
|
|
styles={{
|
2022-04-14 14:58:23 +00:00
|
|
|
option: (provided, state) => ({
|
|
|
|
...provided,
|
|
|
|
color: state.isSelected ? "var(--brand-text-color)" : "black",
|
2022-03-18 18:31:30 +00:00
|
|
|
":active": {
|
2022-04-14 14:58:23 +00:00
|
|
|
backgroundColor: state.isSelected ? "" : "var(--brand-color)",
|
|
|
|
color: "var(--brand-text-color)",
|
2022-03-18 18:31:30 +00:00
|
|
|
},
|
|
|
|
}),
|
|
|
|
}}
|
2021-11-10 11:16:32 +00:00
|
|
|
components={{
|
|
|
|
...components,
|
|
|
|
IndicatorSeparator: () => null,
|
2022-04-14 14:58:23 +00:00
|
|
|
Input: InputComponent,
|
2021-11-10 11:16:32 +00:00
|
|
|
}}
|
2022-04-14 14:58:23 +00:00
|
|
|
className={classNames("text-sm shadow-sm", className)}
|
2021-11-10 11:16:32 +00:00
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
2022-07-14 12:40:53 +00:00
|
|
|
export function SelectWithValidation<
|
|
|
|
Option extends { label: string; value: string },
|
|
|
|
isMulti extends boolean = false,
|
|
|
|
Group extends GroupBase<Option> = GroupBase<Option>
|
|
|
|
>({
|
|
|
|
required = false,
|
|
|
|
onChange,
|
|
|
|
value,
|
|
|
|
...remainingProps
|
|
|
|
}: SelectProps<Option, isMulti, Group> & { required?: boolean }) {
|
|
|
|
const [hiddenInputValue, _setHiddenInputValue] = useState(() => {
|
|
|
|
if (value instanceof Array || !value) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return value.value || "";
|
|
|
|
});
|
|
|
|
|
|
|
|
const setHiddenInputValue = useCallback((value: MultiValue<Option> | SingleValue<Option>) => {
|
|
|
|
let hiddenInputValue = "";
|
|
|
|
if (value instanceof Array) {
|
|
|
|
hiddenInputValue = value.map((val) => val.value).join(",");
|
|
|
|
} else {
|
|
|
|
hiddenInputValue = value?.value || "";
|
|
|
|
}
|
|
|
|
_setHiddenInputValue(hiddenInputValue);
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!value) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
setHiddenInputValue(value);
|
|
|
|
}, [value, setHiddenInputValue]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={classNames("relative", remainingProps.className)}>
|
|
|
|
<Select
|
|
|
|
value={value}
|
|
|
|
{...remainingProps}
|
|
|
|
onChange={(value, ...remainingArgs) => {
|
|
|
|
setHiddenInputValue(value);
|
|
|
|
if (onChange) {
|
|
|
|
onChange(value, ...remainingArgs);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
{required && (
|
|
|
|
<input
|
|
|
|
tabIndex={-1}
|
|
|
|
autoComplete="off"
|
|
|
|
style={{
|
|
|
|
opacity: 0,
|
|
|
|
width: "100%",
|
|
|
|
height: 1,
|
|
|
|
position: "absolute",
|
|
|
|
}}
|
|
|
|
value={hiddenInputValue}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
|
|
onChange={() => {}}
|
|
|
|
// TODO:Not able to get focus to work
|
|
|
|
// onFocus={() => selectRef.current?.focus()}
|
|
|
|
required={required}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2021-11-10 11:16:32 +00:00
|
|
|
export default Select;
|